From dfe2588523a602dd275fb6aadebfe37701dcbb36 Mon Sep 17 00:00:00 2001 From: Jamie Curnow Date: Wed, 9 Oct 2024 18:05:15 +1000 Subject: [PATCH 1/5] Refactor API Schema and validation - /schema now returns full openapi/swagger schema - That schema is used to validate incoming requests - And used as a contract in future integration tests - Moved route files up one level - Fixed incorrect 404 reponses when getting objects - Fixed saving new objects and passing jsonschemavalidation --- backend/.vscode/settings.json | 8 - backend/app.js | 2 +- backend/index.js | 9 +- backend/internal/access-list.js | 4 +- backend/internal/certificate.js | 4 +- backend/internal/dead-host.js | 14 +- backend/internal/proxy-host.js | 14 +- backend/internal/redirection-host.js | 14 +- backend/internal/stream.js | 8 +- backend/internal/user.js | 2 +- backend/lib/validator/api.js | 17 +- backend/lib/validator/index.js | 15 +- backend/package.json | 1 + backend/routes/{api => }/audit-log.js | 12 +- backend/routes/{api => }/main.js | 6 +- .../routes/{api => }/nginx/access_lists.js | 23 +- .../routes/{api => }/nginx/certificates.js | 65 ++- backend/routes/{api => }/nginx/dead_hosts.js | 27 +- backend/routes/{api => }/nginx/proxy_hosts.js | 25 +- .../{api => }/nginx/redirection_hosts.js | 21 +- backend/routes/{api => }/nginx/streams.js | 25 +- backend/routes/{api => }/reports.js | 8 +- backend/routes/{api => }/schema.js | 14 +- backend/routes/{api => }/settings.js | 20 +- backend/routes/{api => }/tokens.js | 17 +- backend/routes/{api => }/users.js | 44 +- backend/schema/common.json | 128 ++++++ .../schema/components/access-list-object.json | 53 +++ .../schema/components/audit-log-object.json | 32 ++ .../schema/components/certificate-list.json | 7 + .../schema/components/certificate-object.json | 66 +++ backend/schema/components/dead-host-list.json | 7 + .../schema/components/dead-host-object.json | 47 +++ backend/schema/components/error-object.json | 14 + backend/schema/components/health-object.json | 38 ++ .../schema/components/permission-object.json | 41 ++ .../schema/components/proxy-host-list.json | 7 + .../schema/components/proxy-host-object.json | 148 +++++++ .../components/redirection-host-list.json | 7 + .../components/redirection-host-object.json | 72 ++++ .../schema/components/security-schemes.json | 6 + backend/schema/components/setting-list.json | 7 + backend/schema/components/setting-object.json | 53 +++ backend/schema/components/stream-list.json | 7 + backend/schema/components/stream-object.json | 60 +++ backend/schema/components/token-object.json | 19 + backend/schema/components/user-list.json | 7 + backend/schema/components/user-object.json | 61 +++ backend/schema/definitions.json | 240 ----------- backend/schema/endpoints/access-lists.json | 236 ----------- backend/schema/endpoints/certificates.json | 173 -------- backend/schema/endpoints/dead-hosts.json | 240 ----------- backend/schema/endpoints/proxy-hosts.json | 387 ------------------ .../schema/endpoints/redirection-hosts.json | 305 -------------- backend/schema/endpoints/settings.json | 99 ----- backend/schema/endpoints/streams.json | 234 ----------- backend/schema/endpoints/tokens.json | 100 ----- backend/schema/endpoints/users.json | 287 ------------- backend/schema/examples.json | 23 -- backend/schema/index.js | 41 ++ backend/schema/index.json | 42 -- backend/schema/paths/audit-log/get.json | 53 +++ backend/schema/paths/get.json | 29 ++ .../schema/paths/nginx/access-lists/get.json | 50 +++ .../nginx/access-lists/listID/delete.json | 39 ++ .../paths/nginx/access-lists/listID/get.json | 49 +++ .../paths/nginx/access-lists/listID/put.json | 164 ++++++++ .../schema/paths/nginx/access-lists/post.json | 155 +++++++ .../nginx/certificates/certID/delete.json | 39 ++ .../certificates/certID/download/get.json | 35 ++ .../paths/nginx/certificates/certID/get.json | 53 +++ .../nginx/certificates/certID/renew/post.json | 54 +++ .../certificates/certID/upload/post.json | 63 +++ .../schema/paths/nginx/certificates/get.json | 54 +++ .../schema/paths/nginx/certificates/post.json | 77 ++++ .../nginx/certificates/test-http/get.json | 40 ++ .../nginx/certificates/validate/post.json | 75 ++++ .../schema/paths/nginx/dead-hosts/get.json | 57 +++ .../paths/nginx/dead-hosts/hostID/delete.json | 39 ++ .../nginx/dead-hosts/hostID/disable/post.json | 59 +++ .../nginx/dead-hosts/hostID/enable/post.json | 59 +++ .../paths/nginx/dead-hosts/hostID/get.json | 56 +++ .../paths/nginx/dead-hosts/hostID/put.json | 110 +++++ .../schema/paths/nginx/dead-hosts/post.json | 95 +++++ .../schema/paths/nginx/proxy-hosts/get.json | 65 +++ .../nginx/proxy-hosts/hostID/delete.json | 39 ++ .../proxy-hosts/hostID/disable/post.json | 59 +++ .../nginx/proxy-hosts/hostID/enable/post.json | 59 +++ .../paths/nginx/proxy-hosts/hostID/get.json | 64 +++ .../paths/nginx/proxy-hosts/hostID/put.json | 145 +++++++ .../schema/paths/nginx/proxy-hosts/post.json | 130 ++++++ .../paths/nginx/redirection-hosts/get.json | 62 +++ .../redirection-hosts/hostID/delete.json | 39 ++ .../hostID/disable/post.json | 59 +++ .../redirection-hosts/hostID/enable/post.json | 59 +++ .../nginx/redirection-hosts/hostID/get.json | 61 +++ .../nginx/redirection-hosts/hostID/put.json | 130 ++++++ .../paths/nginx/redirection-hosts/post.json | 115 ++++++ backend/schema/paths/nginx/streams/get.json | 55 +++ backend/schema/paths/nginx/streams/post.json | 87 ++++ .../paths/nginx/streams/streamID/delete.json | 39 ++ .../nginx/streams/streamID/disable/post.json | 59 +++ .../nginx/streams/streamID/enable/post.json | 59 +++ .../paths/nginx/streams/streamID/get.json | 54 +++ .../paths/nginx/streams/streamID/put.json | 145 +++++++ backend/schema/paths/reports/hosts/get.json | 50 +++ backend/schema/paths/schema/get.json | 10 + backend/schema/paths/settings/get.json | 35 ++ .../schema/paths/settings/settingID/get.json | 46 +++ .../schema/paths/settings/settingID/put.json | 67 +++ backend/schema/paths/tokens/get.json | 30 ++ backend/schema/paths/tokens/post.json | 55 +++ backend/schema/paths/users/get.json | 74 ++++ backend/schema/paths/users/post.json | 88 ++++ .../schema/paths/users/userID/auth/put.json | 79 ++++ backend/schema/paths/users/userID/delete.json | 40 ++ backend/schema/paths/users/userID/get.json | 58 +++ .../schema/paths/users/userID/login/post.json | 73 ++++ .../paths/users/userID/permissions/put.json | 51 +++ backend/schema/paths/users/userID/put.json | 88 ++++ backend/schema/swagger.json | 265 ++++++++++++ backend/yarn.lock | 16 +- docker/docker-compose.dev.yml | 11 + 123 files changed, 5363 insertions(+), 2574 deletions(-) delete mode 100644 backend/.vscode/settings.json rename backend/routes/{api => }/audit-log.js (73%) rename backend/routes/{api => }/main.js (90%) rename backend/routes/{api => }/nginx/access_lists.js (79%) rename backend/routes/{api => }/nginx/certificates.js (80%) rename backend/routes/{api => }/nginx/dead_hosts.js (83%) rename backend/routes/{api => }/nginx/proxy_hosts.js (83%) rename backend/routes/{api => }/nginx/redirection_hosts.js (84%) rename backend/routes/{api => }/nginx/streams.js (84%) rename backend/routes/{api => }/reports.js (67%) rename backend/routes/{api => }/schema.js (71%) rename backend/routes/{api => }/settings.js (74%) rename backend/routes/{api => }/tokens.js (70%) rename backend/routes/{api => }/users.js (79%) create mode 100644 backend/schema/common.json create mode 100644 backend/schema/components/access-list-object.json create mode 100644 backend/schema/components/audit-log-object.json create mode 100644 backend/schema/components/certificate-list.json create mode 100644 backend/schema/components/certificate-object.json create mode 100644 backend/schema/components/dead-host-list.json create mode 100644 backend/schema/components/dead-host-object.json create mode 100644 backend/schema/components/error-object.json create mode 100644 backend/schema/components/health-object.json create mode 100644 backend/schema/components/permission-object.json create mode 100644 backend/schema/components/proxy-host-list.json create mode 100644 backend/schema/components/proxy-host-object.json create mode 100644 backend/schema/components/redirection-host-list.json create mode 100644 backend/schema/components/redirection-host-object.json create mode 100644 backend/schema/components/security-schemes.json create mode 100644 backend/schema/components/setting-list.json create mode 100644 backend/schema/components/setting-object.json create mode 100644 backend/schema/components/stream-list.json create mode 100644 backend/schema/components/stream-object.json create mode 100644 backend/schema/components/token-object.json create mode 100644 backend/schema/components/user-list.json create mode 100644 backend/schema/components/user-object.json delete mode 100644 backend/schema/definitions.json delete mode 100644 backend/schema/endpoints/access-lists.json delete mode 100644 backend/schema/endpoints/certificates.json delete mode 100644 backend/schema/endpoints/dead-hosts.json delete mode 100644 backend/schema/endpoints/proxy-hosts.json delete mode 100644 backend/schema/endpoints/redirection-hosts.json delete mode 100644 backend/schema/endpoints/settings.json delete mode 100644 backend/schema/endpoints/streams.json delete mode 100644 backend/schema/endpoints/tokens.json delete mode 100644 backend/schema/endpoints/users.json delete mode 100644 backend/schema/examples.json create mode 100644 backend/schema/index.js delete mode 100644 backend/schema/index.json create mode 100644 backend/schema/paths/audit-log/get.json create mode 100644 backend/schema/paths/get.json create mode 100644 backend/schema/paths/nginx/access-lists/get.json create mode 100644 backend/schema/paths/nginx/access-lists/listID/delete.json create mode 100644 backend/schema/paths/nginx/access-lists/listID/get.json create mode 100644 backend/schema/paths/nginx/access-lists/listID/put.json create mode 100644 backend/schema/paths/nginx/access-lists/post.json create mode 100644 backend/schema/paths/nginx/certificates/certID/delete.json create mode 100644 backend/schema/paths/nginx/certificates/certID/download/get.json create mode 100644 backend/schema/paths/nginx/certificates/certID/get.json create mode 100644 backend/schema/paths/nginx/certificates/certID/renew/post.json create mode 100644 backend/schema/paths/nginx/certificates/certID/upload/post.json create mode 100644 backend/schema/paths/nginx/certificates/get.json create mode 100644 backend/schema/paths/nginx/certificates/post.json create mode 100644 backend/schema/paths/nginx/certificates/test-http/get.json create mode 100644 backend/schema/paths/nginx/certificates/validate/post.json create mode 100644 backend/schema/paths/nginx/dead-hosts/get.json create mode 100644 backend/schema/paths/nginx/dead-hosts/hostID/delete.json create mode 100644 backend/schema/paths/nginx/dead-hosts/hostID/disable/post.json create mode 100644 backend/schema/paths/nginx/dead-hosts/hostID/enable/post.json create mode 100644 backend/schema/paths/nginx/dead-hosts/hostID/get.json create mode 100644 backend/schema/paths/nginx/dead-hosts/hostID/put.json create mode 100644 backend/schema/paths/nginx/dead-hosts/post.json create mode 100644 backend/schema/paths/nginx/proxy-hosts/get.json create mode 100644 backend/schema/paths/nginx/proxy-hosts/hostID/delete.json create mode 100644 backend/schema/paths/nginx/proxy-hosts/hostID/disable/post.json create mode 100644 backend/schema/paths/nginx/proxy-hosts/hostID/enable/post.json create mode 100644 backend/schema/paths/nginx/proxy-hosts/hostID/get.json create mode 100644 backend/schema/paths/nginx/proxy-hosts/hostID/put.json create mode 100644 backend/schema/paths/nginx/proxy-hosts/post.json create mode 100644 backend/schema/paths/nginx/redirection-hosts/get.json create mode 100644 backend/schema/paths/nginx/redirection-hosts/hostID/delete.json create mode 100644 backend/schema/paths/nginx/redirection-hosts/hostID/disable/post.json create mode 100644 backend/schema/paths/nginx/redirection-hosts/hostID/enable/post.json create mode 100644 backend/schema/paths/nginx/redirection-hosts/hostID/get.json create mode 100644 backend/schema/paths/nginx/redirection-hosts/hostID/put.json create mode 100644 backend/schema/paths/nginx/redirection-hosts/post.json create mode 100644 backend/schema/paths/nginx/streams/get.json create mode 100644 backend/schema/paths/nginx/streams/post.json create mode 100644 backend/schema/paths/nginx/streams/streamID/delete.json create mode 100644 backend/schema/paths/nginx/streams/streamID/disable/post.json create mode 100644 backend/schema/paths/nginx/streams/streamID/enable/post.json create mode 100644 backend/schema/paths/nginx/streams/streamID/get.json create mode 100644 backend/schema/paths/nginx/streams/streamID/put.json create mode 100644 backend/schema/paths/reports/hosts/get.json create mode 100644 backend/schema/paths/schema/get.json create mode 100644 backend/schema/paths/settings/get.json create mode 100644 backend/schema/paths/settings/settingID/get.json create mode 100644 backend/schema/paths/settings/settingID/put.json create mode 100644 backend/schema/paths/tokens/get.json create mode 100644 backend/schema/paths/tokens/post.json create mode 100644 backend/schema/paths/users/get.json create mode 100644 backend/schema/paths/users/post.json create mode 100644 backend/schema/paths/users/userID/auth/put.json create mode 100644 backend/schema/paths/users/userID/delete.json create mode 100644 backend/schema/paths/users/userID/get.json create mode 100644 backend/schema/paths/users/userID/login/post.json create mode 100644 backend/schema/paths/users/userID/permissions/put.json create mode 100644 backend/schema/paths/users/userID/put.json create mode 100644 backend/schema/swagger.json diff --git a/backend/.vscode/settings.json b/backend/.vscode/settings.json deleted file mode 100644 index 4e540ab30..000000000 --- a/backend/.vscode/settings.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "editor.insertSpaces": false, - "editor.formatOnSave": true, - "files.trimTrailingWhitespace": true, - "editor.codeActionsOnSave": { - "source.fixAll.eslint": true - } -} \ No newline at end of file diff --git a/backend/app.js b/backend/app.js index e528a0bbe..59f7def20 100644 --- a/backend/app.js +++ b/backend/app.js @@ -52,7 +52,7 @@ app.use(function (req, res, next) { }); app.use(require('./lib/express/jwt')()); -app.use('/', require('./routes/api/main')); +app.use('/', require('./routes/main')); // production error handler // no stacktraces leaked to user diff --git a/backend/index.js b/backend/index.js index 3d6d60071..551378251 100644 --- a/backend/index.js +++ b/backend/index.js @@ -1,23 +1,20 @@ #!/usr/bin/env node +const schema = require('./schema'); const logger = require('./logger').global; async function appStart () { const migrate = require('./migrate'); const setup = require('./setup'); const app = require('./app'); - const apiValidator = require('./lib/validator/api'); const internalCertificate = require('./internal/certificate'); const internalIpRanges = require('./internal/ip_ranges'); return migrate.latest() .then(setup) - .then(() => { - return apiValidator.loadSchemas; - }) + .then(schema.getCompiledSchema) .then(internalIpRanges.fetch) .then(() => { - internalCertificate.initTimer(); internalIpRanges.initTimer(); @@ -34,7 +31,7 @@ async function appStart () { }); }) .catch((err) => { - logger.error(err.message); + logger.error(err.message, err); setTimeout(appStart, 1000); }); } diff --git a/backend/internal/access-list.js b/backend/internal/access-list.js index 017fc738c..72326be68 100644 --- a/backend/internal/access-list.js +++ b/backend/internal/access-list.js @@ -269,7 +269,7 @@ const internalAccessList = { return query.then(utils.omitRow(omissions())); }) .then((row) => { - if (!row) { + if (!row || !row.id) { throw new error.ItemNotFoundError(data.id); } if (!skip_masking && typeof row.items !== 'undefined' && row.items) { @@ -296,7 +296,7 @@ const internalAccessList = { return internalAccessList.get(access, {id: data.id, expand: ['proxy_hosts', 'items', 'clients']}); }) .then((row) => { - if (!row) { + if (!row || !row.id) { throw new error.ItemNotFoundError(data.id); } diff --git a/backend/internal/certificate.js b/backend/internal/certificate.js index 291056caa..9bdfe695c 100644 --- a/backend/internal/certificate.js +++ b/backend/internal/certificate.js @@ -323,7 +323,7 @@ const internalCertificate = { return query.then(utils.omitRow(omissions())); }) .then((row) => { - if (!row) { + if (!row || !row.id) { throw new error.ItemNotFoundError(data.id); } // Custom omissions @@ -412,7 +412,7 @@ const internalCertificate = { return internalCertificate.get(access, {id: data.id}); }) .then((row) => { - if (!row) { + if (!row || !row.id) { throw new error.ItemNotFoundError(data.id); } diff --git a/backend/internal/dead-host.js b/backend/internal/dead-host.js index 2a6258e96..e672775eb 100644 --- a/backend/internal/dead-host.js +++ b/backend/internal/dead-host.js @@ -48,6 +48,12 @@ const internalDeadHost = { data.owner_user_id = access.token.getUserId(1); data = internalHost.cleanSslHstsData(data); + // Fix for db field not having a default value + // for this optional field. + if (typeof data.advanced_config === 'undefined') { + data.advanced_config = ''; + } + return deadHostModel .query() .insertAndFetch(data) @@ -233,7 +239,7 @@ const internalDeadHost = { return query.then(utils.omitRow(omissions())); }) .then((row) => { - if (!row) { + if (!row || !row.id) { throw new error.ItemNotFoundError(data.id); } // Custom omissions @@ -257,7 +263,7 @@ const internalDeadHost = { return internalDeadHost.get(access, {id: data.id}); }) .then((row) => { - if (!row) { + if (!row || !row.id) { throw new error.ItemNotFoundError(data.id); } @@ -305,7 +311,7 @@ const internalDeadHost = { }); }) .then((row) => { - if (!row) { + if (!row || !row.id) { throw new error.ItemNotFoundError(data.id); } else if (row.enabled) { throw new error.ValidationError('Host is already enabled'); @@ -351,7 +357,7 @@ const internalDeadHost = { return internalDeadHost.get(access, {id: data.id}); }) .then((row) => { - if (!row) { + if (!row || !row.id) { throw new error.ItemNotFoundError(data.id); } else if (!row.enabled) { throw new error.ValidationError('Host is already disabled'); diff --git a/backend/internal/proxy-host.js b/backend/internal/proxy-host.js index dbff1147d..0ea168789 100644 --- a/backend/internal/proxy-host.js +++ b/backend/internal/proxy-host.js @@ -48,6 +48,12 @@ const internalProxyHost = { data.owner_user_id = access.token.getUserId(1); data = internalHost.cleanSslHstsData(data); + // Fix for db field not having a default value + // for this optional field. + if (typeof data.advanced_config === 'undefined') { + data.advanced_config = ''; + } + return proxyHostModel .query() .insertAndFetch(data) @@ -239,7 +245,7 @@ const internalProxyHost = { return query.then(utils.omitRow(omissions())); }) .then((row) => { - if (!row) { + if (!row || !row.id) { throw new error.ItemNotFoundError(data.id); } row = internalHost.cleanRowCertificateMeta(row); @@ -264,7 +270,7 @@ const internalProxyHost = { return internalProxyHost.get(access, {id: data.id}); }) .then((row) => { - if (!row) { + if (!row || !row.id) { throw new error.ItemNotFoundError(data.id); } @@ -312,7 +318,7 @@ const internalProxyHost = { }); }) .then((row) => { - if (!row) { + if (!row || !row.id) { throw new error.ItemNotFoundError(data.id); } else if (row.enabled) { throw new error.ValidationError('Host is already enabled'); @@ -358,7 +364,7 @@ const internalProxyHost = { return internalProxyHost.get(access, {id: data.id}); }) .then((row) => { - if (!row) { + if (!row || !row.id) { throw new error.ItemNotFoundError(data.id); } else if (!row.enabled) { throw new error.ValidationError('Host is already disabled'); diff --git a/backend/internal/redirection-host.js b/backend/internal/redirection-host.js index 775d94f3a..41ff5b093 100644 --- a/backend/internal/redirection-host.js +++ b/backend/internal/redirection-host.js @@ -48,6 +48,12 @@ const internalRedirectionHost = { data.owner_user_id = access.token.getUserId(1); data = internalHost.cleanSslHstsData(data); + // Fix for db field not having a default value + // for this optional field. + if (typeof data.advanced_config === 'undefined') { + data.advanced_config = ''; + } + return redirectionHostModel .query() .insertAndFetch(data) @@ -232,7 +238,7 @@ const internalRedirectionHost = { return query.then(utils.omitRow(omissions())); }) .then((row) => { - if (!row) { + if (!row || !row.id) { throw new error.ItemNotFoundError(data.id); } row = internalHost.cleanRowCertificateMeta(row); @@ -257,7 +263,7 @@ const internalRedirectionHost = { return internalRedirectionHost.get(access, {id: data.id}); }) .then((row) => { - if (!row) { + if (!row || !row.id) { throw new error.ItemNotFoundError(data.id); } @@ -305,7 +311,7 @@ const internalRedirectionHost = { }); }) .then((row) => { - if (!row) { + if (!row || !row.id) { throw new error.ItemNotFoundError(data.id); } else if (row.enabled) { throw new error.ValidationError('Host is already enabled'); @@ -351,7 +357,7 @@ const internalRedirectionHost = { return internalRedirectionHost.get(access, {id: data.id}); }) .then((row) => { - if (!row) { + if (!row || !row.id) { throw new error.ItemNotFoundError(data.id); } else if (!row.enabled) { throw new error.ValidationError('Host is already disabled'); diff --git a/backend/internal/stream.js b/backend/internal/stream.js index a159cfdd3..ee88d46fc 100644 --- a/backend/internal/stream.js +++ b/backend/internal/stream.js @@ -128,7 +128,7 @@ const internalStream = { return query.then(utils.omitRow(omissions())); }) .then((row) => { - if (!row) { + if (!row || !row.id) { throw new error.ItemNotFoundError(data.id); } // Custom omissions @@ -152,7 +152,7 @@ const internalStream = { return internalStream.get(access, {id: data.id}); }) .then((row) => { - if (!row) { + if (!row || !row.id) { throw new error.ItemNotFoundError(data.id); } @@ -200,7 +200,7 @@ const internalStream = { }); }) .then((row) => { - if (!row) { + if (!row || !row.id) { throw new error.ItemNotFoundError(data.id); } else if (row.enabled) { throw new error.ValidationError('Host is already enabled'); @@ -246,7 +246,7 @@ const internalStream = { return internalStream.get(access, {id: data.id}); }) .then((row) => { - if (!row) { + if (!row || !row.id) { throw new error.ItemNotFoundError(data.id); } else if (!row.enabled) { throw new error.ValidationError('Host is already disabled'); diff --git a/backend/internal/user.js b/backend/internal/user.js index a1d90447f..742ab65d3 100644 --- a/backend/internal/user.js +++ b/backend/internal/user.js @@ -194,7 +194,7 @@ const internalUser = { return query.then(utils.omitRow(omissions())); }) .then((row) => { - if (!row) { + if (!row || !row.id) { throw new error.ItemNotFoundError(data.id); } // Custom omissions diff --git a/backend/lib/validator/api.js b/backend/lib/validator/api.js index 3f51b5969..c0876ab32 100644 --- a/backend/lib/validator/api.js +++ b/backend/lib/validator/api.js @@ -1,6 +1,4 @@ -const error = require('../error'); -const path = require('path'); -const parser = require('json-schema-ref-parser'); +const error = require('../error'); const ajv = require('ajv')({ verbose: true, @@ -17,8 +15,14 @@ const ajv = require('ajv')({ */ function apiValidator (schema, payload/*, description*/) { return new Promise(function Promise_apiValidator (resolve, reject) { + if (schema === null) { + reject(new error.ValidationError('Schema is undefined')); + return; + } + if (typeof payload === 'undefined') { reject(new error.ValidationError('Payload is undefined')); + return; } let validate = ajv.compile(schema); @@ -35,11 +39,4 @@ function apiValidator (schema, payload/*, description*/) { }); } -apiValidator.loadSchemas = parser - .dereference(path.resolve('schema/index.json')) - .then((schema) => { - ajv.addSchema(schema); - return schema; - }); - module.exports = apiValidator; diff --git a/backend/lib/validator/index.js b/backend/lib/validator/index.js index d09c9be5f..3c5265b17 100644 --- a/backend/lib/validator/index.js +++ b/backend/lib/validator/index.js @@ -1,6 +1,6 @@ -const _ = require('lodash'); -const error = require('../error'); -const definitions = require('../../schema/definitions.json'); +const _ = require('lodash'); +const error = require('../error'); +const commonDefinitions = require('../../schema/common.json'); RegExp.prototype.toJSON = RegExp.prototype.toString; @@ -9,9 +9,7 @@ const ajv = require('ajv')({ allErrors: true, format: 'full', // strict regexes for format checks coerceTypes: true, - schemas: [ - definitions - ] + schemas: [commonDefinitions] }); /** @@ -27,21 +25,18 @@ function validator (schema, payload) { } else { try { let validate = ajv.compile(schema); + let valid = validate(payload); - let valid = validate(payload); if (valid && !validate.errors) { resolve(_.cloneDeep(payload)); } else { let message = ajv.errorsText(validate.errors); reject(new error.InternalValidationError(message)); } - } catch (err) { reject(err); } - } - }); } diff --git a/backend/package.json b/backend/package.json index b938c9a9c..379c6e68c 100644 --- a/backend/package.json +++ b/backend/package.json @@ -4,6 +4,7 @@ "description": "A beautiful interface for creating Nginx endpoints", "main": "js/index.js", "dependencies": { + "@apidevtools/json-schema-ref-parser": "^11.7.0", "ajv": "^6.12.0", "archiver": "^5.3.0", "batchflow": "^0.4.0", diff --git a/backend/routes/api/audit-log.js b/backend/routes/audit-log.js similarity index 73% rename from backend/routes/api/audit-log.js rename to backend/routes/audit-log.js index 8a2490c3f..6467a63d2 100644 --- a/backend/routes/api/audit-log.js +++ b/backend/routes/audit-log.js @@ -1,7 +1,7 @@ const express = require('express'); -const validator = require('../../lib/validator'); -const jwtdecode = require('../../lib/express/jwt-decode'); -const internalAuditLog = require('../../internal/audit-log'); +const validator = require('../lib/validator'); +const jwtdecode = require('../lib/express/jwt-decode'); +const internalAuditLog = require('../internal/audit-log'); let router = express.Router({ caseSensitive: true, @@ -14,7 +14,7 @@ let router = express.Router({ */ router .route('/') - .options((req, res) => { + .options((_, res) => { res.sendStatus(204); }) .all(jwtdecode()) @@ -29,10 +29,10 @@ router additionalProperties: false, properties: { expand: { - $ref: 'definitions#/definitions/expand' + $ref: 'common#/definitions/expand' }, query: { - $ref: 'definitions#/definitions/query' + $ref: 'common#/definitions/query' } } }, { diff --git a/backend/routes/api/main.js b/backend/routes/main.js similarity index 90% rename from backend/routes/api/main.js rename to backend/routes/main.js index 33cbbc21f..b97096d0e 100644 --- a/backend/routes/api/main.js +++ b/backend/routes/main.js @@ -1,6 +1,6 @@ const express = require('express'); -const pjson = require('../../package.json'); -const error = require('../../lib/error'); +const pjson = require('../package.json'); +const error = require('../lib/error'); let router = express.Router({ caseSensitive: true, @@ -43,7 +43,7 @@ router.use('/nginx/certificates', require('./nginx/certificates')); * * ALL /api/* */ -router.all(/(.+)/, function (req, res, next) { +router.all(/(.+)/, function (req, _, next) { req.params.page = req.params['0']; next(new error.ItemNotFoundError(req.params.page)); }); diff --git a/backend/routes/api/nginx/access_lists.js b/backend/routes/nginx/access_lists.js similarity index 79% rename from backend/routes/api/nginx/access_lists.js rename to backend/routes/nginx/access_lists.js index d55c3ae12..79e920ddb 100644 --- a/backend/routes/api/nginx/access_lists.js +++ b/backend/routes/nginx/access_lists.js @@ -1,8 +1,9 @@ const express = require('express'); -const validator = require('../../../lib/validator'); -const jwtdecode = require('../../../lib/express/jwt-decode'); -const internalAccessList = require('../../../internal/access-list'); -const apiValidator = require('../../../lib/validator/api'); +const validator = require('../../lib/validator'); +const jwtdecode = require('../../lib/express/jwt-decode'); +const apiValidator = require('../../lib/validator/api'); +const internalAccessList = require('../../internal/access-list'); +const schema = require('../../schema'); let router = express.Router({ caseSensitive: true, @@ -30,10 +31,10 @@ router additionalProperties: false, properties: { expand: { - $ref: 'definitions#/definitions/expand' + $ref: 'common#/definitions/expand' }, query: { - $ref: 'definitions#/definitions/query' + $ref: 'common#/definitions/query' } } }, { @@ -56,7 +57,7 @@ router * Create a new access-list */ .post((req, res, next) => { - apiValidator({$ref: 'endpoints/access-lists#/links/1/schema'}, req.body) + apiValidator(schema.getValidationSchema('/nginx/access-lists', 'post'), req.body) .then((payload) => { return internalAccessList.create(res.locals.access, payload); }) @@ -74,7 +75,7 @@ router */ router .route('/:list_id') - .options((req, res) => { + .options((_, res) => { res.sendStatus(204); }) .all(jwtdecode()) @@ -90,10 +91,10 @@ router additionalProperties: false, properties: { list_id: { - $ref: 'definitions#/definitions/id' + $ref: 'common#/definitions/id' }, expand: { - $ref: 'definitions#/definitions/expand' + $ref: 'common#/definitions/expand' } } }, { @@ -119,7 +120,7 @@ router * Update and existing access-list */ .put((req, res, next) => { - apiValidator({$ref: 'endpoints/access-lists#/links/2/schema'}, req.body) + apiValidator(schema.getValidationSchema('/nginx/access-lists/{listID}', 'put'), req.body) .then((payload) => { payload.id = parseInt(req.params.list_id, 10); return internalAccessList.update(res.locals.access, payload); diff --git a/backend/routes/api/nginx/certificates.js b/backend/routes/nginx/certificates.js similarity index 80% rename from backend/routes/api/nginx/certificates.js rename to backend/routes/nginx/certificates.js index ffdfb515d..b6ad7c69c 100644 --- a/backend/routes/api/nginx/certificates.js +++ b/backend/routes/nginx/certificates.js @@ -1,8 +1,10 @@ const express = require('express'); -const validator = require('../../../lib/validator'); -const jwtdecode = require('../../../lib/express/jwt-decode'); -const internalCertificate = require('../../../internal/certificate'); -const apiValidator = require('../../../lib/validator/api'); +const error = require('../../lib/error'); +const validator = require('../../lib/validator'); +const jwtdecode = require('../../lib/express/jwt-decode'); +const apiValidator = require('../../lib/validator/api'); +const internalCertificate = require('../../internal/certificate'); +const schema = require('../../schema'); let router = express.Router({ caseSensitive: true, @@ -15,7 +17,7 @@ let router = express.Router({ */ router .route('/') - .options((req, res) => { + .options((_, res) => { res.sendStatus(204); }) .all(jwtdecode()) @@ -30,10 +32,10 @@ router additionalProperties: false, properties: { expand: { - $ref: 'definitions#/definitions/expand' + $ref: 'common#/definitions/expand' }, query: { - $ref: 'definitions#/definitions/query' + $ref: 'common#/definitions/query' } } }, { @@ -56,7 +58,7 @@ router * Create a new certificate */ .post((req, res, next) => { - apiValidator({$ref: 'endpoints/certificates#/links/1/schema'}, req.body) + apiValidator(schema.getValidationSchema('/nginx/certificates', 'post'), req.body) .then((payload) => { req.setTimeout(900000); // 15 minutes timeout return internalCertificate.create(res.locals.access, payload); @@ -75,17 +77,22 @@ router */ router .route('/test-http') - .options((req, res) => { + .options((_, res) => { res.sendStatus(204); }) .all(jwtdecode()) -/** - * GET /api/nginx/certificates/test-http - * - * Test HTTP challenge for domains - */ + /** + * GET /api/nginx/certificates/test-http + * + * Test HTTP challenge for domains + */ .get((req, res, next) => { + if (req.query.domains === undefined) { + next(new error.ValidationError('Domains are required as query parameters')); + return; + } + internalCertificate.testHttpsChallenge(res.locals.access, JSON.parse(req.query.domains)) .then((result) => { res.status(200) @@ -101,7 +108,7 @@ router */ router .route('/:certificate_id') - .options((req, res) => { + .options((_, res) => { res.sendStatus(204); }) .all(jwtdecode()) @@ -117,10 +124,10 @@ router additionalProperties: false, properties: { certificate_id: { - $ref: 'definitions#/definitions/id' + $ref: 'common#/definitions/id' }, expand: { - $ref: 'definitions#/definitions/expand' + $ref: 'common#/definitions/expand' } } }, { @@ -140,24 +147,6 @@ router .catch(next); }) - /** - * PUT /api/nginx/certificates/123 - * - * Update and existing certificate - */ - .put((req, res, next) => { - apiValidator({$ref: 'endpoints/certificates#/links/2/schema'}, req.body) - .then((payload) => { - payload.id = parseInt(req.params.certificate_id, 10); - return internalCertificate.update(res.locals.access, payload); - }) - .then((result) => { - res.status(200) - .send(result); - }) - .catch(next); - }) - /** * DELETE /api/nginx/certificates/123 * @@ -179,7 +168,7 @@ router */ router .route('/:certificate_id/upload') - .options((req, res) => { + .options((_, res) => { res.sendStatus(204); }) .all(jwtdecode()) @@ -213,7 +202,7 @@ router */ router .route('/:certificate_id/renew') - .options((req, res) => { + .options((_, res) => { res.sendStatus(204); }) .all(jwtdecode()) @@ -270,7 +259,7 @@ router */ router .route('/validate') - .options((req, res) => { + .options((_, res) => { res.sendStatus(204); }) .all(jwtdecode()) diff --git a/backend/routes/api/nginx/dead_hosts.js b/backend/routes/nginx/dead_hosts.js similarity index 83% rename from backend/routes/api/nginx/dead_hosts.js rename to backend/routes/nginx/dead_hosts.js index 08b58f2de..4523d3e42 100644 --- a/backend/routes/api/nginx/dead_hosts.js +++ b/backend/routes/nginx/dead_hosts.js @@ -1,8 +1,9 @@ const express = require('express'); -const validator = require('../../../lib/validator'); -const jwtdecode = require('../../../lib/express/jwt-decode'); -const internalDeadHost = require('../../../internal/dead-host'); -const apiValidator = require('../../../lib/validator/api'); +const validator = require('../../lib/validator'); +const jwtdecode = require('../../lib/express/jwt-decode'); +const apiValidator = require('../../lib/validator/api'); +const internalDeadHost = require('../../internal/dead-host'); +const schema = require('../../schema'); let router = express.Router({ caseSensitive: true, @@ -15,7 +16,7 @@ let router = express.Router({ */ router .route('/') - .options((req, res) => { + .options((_, res) => { res.sendStatus(204); }) .all(jwtdecode()) @@ -30,10 +31,10 @@ router additionalProperties: false, properties: { expand: { - $ref: 'definitions#/definitions/expand' + $ref: 'common#/definitions/expand' }, query: { - $ref: 'definitions#/definitions/query' + $ref: 'common#/definitions/query' } } }, { @@ -56,7 +57,7 @@ router * Create a new dead-host */ .post((req, res, next) => { - apiValidator({$ref: 'endpoints/dead-hosts#/links/1/schema'}, req.body) + apiValidator(schema.getValidationSchema('/nginx/dead-hosts', 'post'), req.body) .then((payload) => { return internalDeadHost.create(res.locals.access, payload); }) @@ -90,10 +91,10 @@ router additionalProperties: false, properties: { host_id: { - $ref: 'definitions#/definitions/id' + $ref: 'common#/definitions/id' }, expand: { - $ref: 'definitions#/definitions/expand' + $ref: 'common#/definitions/expand' } } }, { @@ -119,7 +120,7 @@ router * Update and existing dead-host */ .put((req, res, next) => { - apiValidator({$ref: 'endpoints/dead-hosts#/links/2/schema'}, req.body) + apiValidator(schema.getValidationSchema('/nginx/dead-hosts/{hostID}', 'put'), req.body) .then((payload) => { payload.id = parseInt(req.params.host_id, 10); return internalDeadHost.update(res.locals.access, payload); @@ -152,7 +153,7 @@ router */ router .route('/:host_id/enable') - .options((req, res) => { + .options((_, res) => { res.sendStatus(204); }) .all(jwtdecode()) @@ -176,7 +177,7 @@ router */ router .route('/:host_id/disable') - .options((req, res) => { + .options((_, res) => { res.sendStatus(204); }) .all(jwtdecode()) diff --git a/backend/routes/api/nginx/proxy_hosts.js b/backend/routes/nginx/proxy_hosts.js similarity index 83% rename from backend/routes/api/nginx/proxy_hosts.js rename to backend/routes/nginx/proxy_hosts.js index 6f933c3d3..6ace41954 100644 --- a/backend/routes/api/nginx/proxy_hosts.js +++ b/backend/routes/nginx/proxy_hosts.js @@ -1,8 +1,9 @@ const express = require('express'); -const validator = require('../../../lib/validator'); -const jwtdecode = require('../../../lib/express/jwt-decode'); -const internalProxyHost = require('../../../internal/proxy-host'); -const apiValidator = require('../../../lib/validator/api'); +const validator = require('../../lib/validator'); +const jwtdecode = require('../../lib/express/jwt-decode'); +const apiValidator = require('../../lib/validator/api'); +const internalProxyHost = require('../../internal/proxy-host'); +const schema = require('../../schema'); let router = express.Router({ caseSensitive: true, @@ -30,10 +31,10 @@ router additionalProperties: false, properties: { expand: { - $ref: 'definitions#/definitions/expand' + $ref: 'common#/definitions/expand' }, query: { - $ref: 'definitions#/definitions/query' + $ref: 'common#/definitions/query' } } }, { @@ -56,7 +57,7 @@ router * Create a new proxy-host */ .post((req, res, next) => { - apiValidator({$ref: 'endpoints/proxy-hosts#/links/1/schema'}, req.body) + apiValidator(schema.getValidationSchema('/nginx/proxy-hosts', 'post'), req.body) .then((payload) => { return internalProxyHost.create(res.locals.access, payload); }) @@ -90,10 +91,10 @@ router additionalProperties: false, properties: { host_id: { - $ref: 'definitions#/definitions/id' + $ref: 'common#/definitions/id' }, expand: { - $ref: 'definitions#/definitions/expand' + $ref: 'common#/definitions/expand' } } }, { @@ -119,7 +120,7 @@ router * Update and existing proxy-host */ .put((req, res, next) => { - apiValidator({$ref: 'endpoints/proxy-hosts#/links/2/schema'}, req.body) + apiValidator(schema.getValidationSchema('/nginx/proxy-hosts/{hostID}', 'put'), req.body) .then((payload) => { payload.id = parseInt(req.params.host_id, 10); return internalProxyHost.update(res.locals.access, payload); @@ -152,7 +153,7 @@ router */ router .route('/:host_id/enable') - .options((req, res) => { + .options((_, res) => { res.sendStatus(204); }) .all(jwtdecode()) @@ -176,7 +177,7 @@ router */ router .route('/:host_id/disable') - .options((req, res) => { + .options((_, res) => { res.sendStatus(204); }) .all(jwtdecode()) diff --git a/backend/routes/api/nginx/redirection_hosts.js b/backend/routes/nginx/redirection_hosts.js similarity index 84% rename from backend/routes/api/nginx/redirection_hosts.js rename to backend/routes/nginx/redirection_hosts.js index 4d44c1126..de334e74e 100644 --- a/backend/routes/api/nginx/redirection_hosts.js +++ b/backend/routes/nginx/redirection_hosts.js @@ -1,8 +1,9 @@ const express = require('express'); -const validator = require('../../../lib/validator'); -const jwtdecode = require('../../../lib/express/jwt-decode'); -const internalRedirectionHost = require('../../../internal/redirection-host'); -const apiValidator = require('../../../lib/validator/api'); +const validator = require('../../lib/validator'); +const jwtdecode = require('../../lib/express/jwt-decode'); +const apiValidator = require('../../lib/validator/api'); +const internalRedirectionHost = require('../../internal/redirection-host'); +const schema = require('../../schema'); let router = express.Router({ caseSensitive: true, @@ -30,10 +31,10 @@ router additionalProperties: false, properties: { expand: { - $ref: 'definitions#/definitions/expand' + $ref: 'common#/definitions/expand' }, query: { - $ref: 'definitions#/definitions/query' + $ref: 'common#/definitions/query' } } }, { @@ -56,7 +57,7 @@ router * Create a new redirection-host */ .post((req, res, next) => { - apiValidator({$ref: 'endpoints/redirection-hosts#/links/1/schema'}, req.body) + apiValidator(schema.getValidationSchema('/nginx/redirection-hosts', 'post'), req.body) .then((payload) => { return internalRedirectionHost.create(res.locals.access, payload); }) @@ -90,10 +91,10 @@ router additionalProperties: false, properties: { host_id: { - $ref: 'definitions#/definitions/id' + $ref: 'common#/definitions/id' }, expand: { - $ref: 'definitions#/definitions/expand' + $ref: 'common#/definitions/expand' } } }, { @@ -119,7 +120,7 @@ router * Update and existing redirection-host */ .put((req, res, next) => { - apiValidator({$ref: 'endpoints/redirection-hosts#/links/2/schema'}, req.body) + apiValidator(schema.getValidationSchema('/nginx/redirection-hosts/{hostID}', 'put'), req.body) .then((payload) => { payload.id = parseInt(req.params.host_id, 10); return internalRedirectionHost.update(res.locals.access, payload); diff --git a/backend/routes/api/nginx/streams.js b/backend/routes/nginx/streams.js similarity index 84% rename from backend/routes/api/nginx/streams.js rename to backend/routes/nginx/streams.js index 5e3fc28fe..1f68c1989 100644 --- a/backend/routes/api/nginx/streams.js +++ b/backend/routes/nginx/streams.js @@ -1,8 +1,9 @@ const express = require('express'); -const validator = require('../../../lib/validator'); -const jwtdecode = require('../../../lib/express/jwt-decode'); -const internalStream = require('../../../internal/stream'); -const apiValidator = require('../../../lib/validator/api'); +const validator = require('../../lib/validator'); +const jwtdecode = require('../../lib/express/jwt-decode'); +const apiValidator = require('../../lib/validator/api'); +const internalStream = require('../../internal/stream'); +const schema = require('../../schema'); let router = express.Router({ caseSensitive: true, @@ -30,10 +31,10 @@ router additionalProperties: false, properties: { expand: { - $ref: 'definitions#/definitions/expand' + $ref: 'common#/definitions/expand' }, query: { - $ref: 'definitions#/definitions/query' + $ref: 'common#/definitions/query' } } }, { @@ -56,7 +57,7 @@ router * Create a new stream */ .post((req, res, next) => { - apiValidator({$ref: 'endpoints/streams#/links/1/schema'}, req.body) + apiValidator(schema.getValidationSchema('/nginx/streams', 'post'), req.body) .then((payload) => { return internalStream.create(res.locals.access, payload); }) @@ -90,10 +91,10 @@ router additionalProperties: false, properties: { stream_id: { - $ref: 'definitions#/definitions/id' + $ref: 'common#/definitions/id' }, expand: { - $ref: 'definitions#/definitions/expand' + $ref: 'common#/definitions/expand' } } }, { @@ -119,7 +120,7 @@ router * Update and existing stream */ .put((req, res, next) => { - apiValidator({$ref: 'endpoints/streams#/links/2/schema'}, req.body) + apiValidator(schema.getValidationSchema('/nginx/streams/{streamID}', 'put'), req.body) .then((payload) => { payload.id = parseInt(req.params.stream_id, 10); return internalStream.update(res.locals.access, payload); @@ -152,7 +153,7 @@ router */ router .route('/:host_id/enable') - .options((req, res) => { + .options((_, res) => { res.sendStatus(204); }) .all(jwtdecode()) @@ -176,7 +177,7 @@ router */ router .route('/:host_id/disable') - .options((req, res) => { + .options((_, res) => { res.sendStatus(204); }) .all(jwtdecode()) diff --git a/backend/routes/api/reports.js b/backend/routes/reports.js similarity index 67% rename from backend/routes/api/reports.js rename to backend/routes/reports.js index 9e2c98c89..98c6cf86d 100644 --- a/backend/routes/api/reports.js +++ b/backend/routes/reports.js @@ -1,6 +1,6 @@ const express = require('express'); -const jwtdecode = require('../../lib/express/jwt-decode'); -const internalReport = require('../../internal/report'); +const jwtdecode = require('../lib/express/jwt-decode'); +const internalReport = require('../internal/report'); let router = express.Router({ caseSensitive: true, @@ -10,14 +10,14 @@ let router = express.Router({ router .route('/hosts') - .options((req, res) => { + .options((_, res) => { res.sendStatus(204); }) /** * GET /reports/hosts */ - .get(jwtdecode(), (req, res, next) => { + .get(jwtdecode(), (_, res, next) => { internalReport.getHostsReport(res.locals.access) .then((data) => { res.status(200) diff --git a/backend/routes/api/schema.js b/backend/routes/schema.js similarity index 71% rename from backend/routes/api/schema.js rename to backend/routes/schema.js index fc6bd5bdf..fc3e48b6c 100644 --- a/backend/routes/api/schema.js +++ b/backend/routes/schema.js @@ -1,8 +1,8 @@ -const express = require('express'); -const swaggerJSON = require('../../doc/api.swagger.json'); -const PACKAGE = require('../../package.json'); +const express = require('express'); +const schema = require('../schema'); +const PACKAGE = require('../package.json'); -let router = express.Router({ +const router = express.Router({ caseSensitive: true, strict: true, mergeParams: true @@ -10,14 +10,16 @@ let router = express.Router({ router .route('/') - .options((req, res) => { + .options((_, res) => { res.sendStatus(204); }) /** * GET /schema */ - .get((req, res/*, next*/) => { + .get(async (req, res) => { + let swaggerJSON = await schema.getCompiledSchema(); + let proto = req.protocol; if (typeof req.headers['x-forwarded-proto'] !== 'undefined' && req.headers['x-forwarded-proto']) { proto = req.headers['x-forwarded-proto']; diff --git a/backend/routes/api/settings.js b/backend/routes/settings.js similarity index 74% rename from backend/routes/api/settings.js rename to backend/routes/settings.js index d08b2bf5c..dac4c3d1a 100644 --- a/backend/routes/api/settings.js +++ b/backend/routes/settings.js @@ -1,8 +1,9 @@ const express = require('express'); -const validator = require('../../lib/validator'); -const jwtdecode = require('../../lib/express/jwt-decode'); -const internalSetting = require('../../internal/setting'); -const apiValidator = require('../../lib/validator/api'); +const validator = require('../lib/validator'); +const jwtdecode = require('../lib/express/jwt-decode'); +const apiValidator = require('../lib/validator/api'); +const internalSetting = require('../internal/setting'); +const schema = require('../schema'); let router = express.Router({ caseSensitive: true, @@ -15,7 +16,7 @@ let router = express.Router({ */ router .route('/') - .options((req, res) => { + .options((_, res) => { res.sendStatus(204); }) .all(jwtdecode()) @@ -25,7 +26,7 @@ router * * Retrieve all settings */ - .get((req, res, next) => { + .get((_, res, next) => { internalSetting.getAll(res.locals.access) .then((rows) => { res.status(200) @@ -41,7 +42,7 @@ router */ router .route('/:setting_id') - .options((req, res) => { + .options((_, res) => { res.sendStatus(204); }) .all(jwtdecode()) @@ -57,7 +58,8 @@ router additionalProperties: false, properties: { setting_id: { - $ref: 'definitions#/definitions/setting_id' + type: 'string', + minLength: 1 } } }, { @@ -81,7 +83,7 @@ router * Update and existing setting */ .put((req, res, next) => { - apiValidator({$ref: 'endpoints/settings#/links/1/schema'}, req.body) + apiValidator(schema.getValidationSchema('/settings/{settingID}', 'put'), req.body) .then((payload) => { payload.id = req.params.setting_id; return internalSetting.update(res.locals.access, payload); diff --git a/backend/routes/api/tokens.js b/backend/routes/tokens.js similarity index 70% rename from backend/routes/api/tokens.js rename to backend/routes/tokens.js index a21f998ae..72d01d41d 100644 --- a/backend/routes/api/tokens.js +++ b/backend/routes/tokens.js @@ -1,7 +1,8 @@ const express = require('express'); -const jwtdecode = require('../../lib/express/jwt-decode'); -const internalToken = require('../../internal/token'); -const apiValidator = require('../../lib/validator/api'); +const jwtdecode = require('../lib/express/jwt-decode'); +const apiValidator = require('../lib/validator/api'); +const internalToken = require('../internal/token'); +const schema = require('../schema'); let router = express.Router({ caseSensitive: true, @@ -11,7 +12,7 @@ let router = express.Router({ router .route('/') - .options((req, res) => { + .options((_, res) => { res.sendStatus(204); }) @@ -39,11 +40,9 @@ router * * Create a new Token */ - .post((req, res, next) => { - apiValidator({$ref: 'endpoints/tokens#/links/0/schema'}, req.body) - .then((payload) => { - return internalToken.getTokenFromEmail(payload); - }) + .post(async (req, res, next) => { + apiValidator(schema.getValidationSchema('/tokens', 'post'), req.body) + .then(internalToken.getTokenFromEmail) .then((data) => { res.status(200) .send(data); diff --git a/backend/routes/api/users.js b/backend/routes/users.js similarity index 79% rename from backend/routes/api/users.js rename to backend/routes/users.js index 1c6bd0ad2..475156675 100644 --- a/backend/routes/api/users.js +++ b/backend/routes/users.js @@ -1,9 +1,10 @@ const express = require('express'); -const validator = require('../../lib/validator'); -const jwtdecode = require('../../lib/express/jwt-decode'); -const userIdFromMe = require('../../lib/express/user-id-from-me'); -const internalUser = require('../../internal/user'); -const apiValidator = require('../../lib/validator/api'); +const validator = require('../lib/validator'); +const jwtdecode = require('../lib/express/jwt-decode'); +const userIdFromMe = require('../lib/express/user-id-from-me'); +const internalUser = require('../internal/user'); +const apiValidator = require('../lib/validator/api'); +const schema = require('../schema'); let router = express.Router({ caseSensitive: true, @@ -16,7 +17,7 @@ let router = express.Router({ */ router .route('/') - .options((req, res) => { + .options((_, res) => { res.sendStatus(204); }) .all(jwtdecode()) @@ -31,10 +32,10 @@ router additionalProperties: false, properties: { expand: { - $ref: 'definitions#/definitions/expand' + $ref: 'common#/definitions/expand' }, query: { - $ref: 'definitions#/definitions/query' + $ref: 'common#/definitions/query' } } }, { @@ -48,7 +49,11 @@ router res.status(200) .send(users); }) - .catch(next); + .catch((err) => { + console.log(err); + next(err); + }); + //.catch(next); }) /** @@ -57,7 +62,7 @@ router * Create a new User */ .post((req, res, next) => { - apiValidator({$ref: 'endpoints/users#/links/1/schema'}, req.body) + apiValidator(schema.getValidationSchema('/users', 'post'), req.body) .then((payload) => { return internalUser.create(res.locals.access, payload); }) @@ -75,7 +80,7 @@ router */ router .route('/:user_id') - .options((req, res) => { + .options((_, res) => { res.sendStatus(204); }) .all(jwtdecode()) @@ -92,10 +97,10 @@ router additionalProperties: false, properties: { user_id: { - $ref: 'definitions#/definitions/id' + $ref: 'common#/definitions/id' }, expand: { - $ref: 'definitions#/definitions/expand' + $ref: 'common#/definitions/expand' } } }, { @@ -113,7 +118,10 @@ router res.status(200) .send(user); }) - .catch(next); + .catch((err) => { + console.log(err); + next(err); + }); }) /** @@ -122,7 +130,7 @@ router * Update and existing user */ .put((req, res, next) => { - apiValidator({$ref: 'endpoints/users#/links/2/schema'}, req.body) + apiValidator(schema.getValidationSchema('/users/{userID}', 'put'), req.body) .then((payload) => { payload.id = req.params.user_id; return internalUser.update(res.locals.access, payload); @@ -167,7 +175,7 @@ router * Update password for a user */ .put((req, res, next) => { - apiValidator({$ref: 'endpoints/users#/links/4/schema'}, req.body) + apiValidator(schema.getValidationSchema('/users/{userID}/auth', 'put'), req.body) .then((payload) => { payload.id = req.params.user_id; return internalUser.setPassword(res.locals.access, payload); @@ -198,7 +206,7 @@ router * Set some or all permissions for a user */ .put((req, res, next) => { - apiValidator({$ref: 'endpoints/users#/links/5/schema'}, req.body) + apiValidator(schema.getValidationSchema('/users/{userID}/permissions', 'put'), req.body) .then((payload) => { payload.id = req.params.user_id; return internalUser.setPermissions(res.locals.access, payload); @@ -217,7 +225,7 @@ router */ router .route('/:user_id/login') - .options((req, res) => { + .options((_, res) => { res.sendStatus(204); }) .all(jwtdecode()) diff --git a/backend/schema/common.json b/backend/schema/common.json new file mode 100644 index 000000000..dd8247a4b --- /dev/null +++ b/backend/schema/common.json @@ -0,0 +1,128 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "common", + "definitions": { + "id": { + "description": "Unique identifier", + "example": 123456, + "readOnly": true, + "type": "integer", + "minimum": 1 + }, + "expand": { + "anyOf": [ + { + "type": "null" + }, + { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } + } + ] + }, + "query": { + "anyOf": [ + { + "type": "null" + }, + { + "type": "string", + "minLength": 1, + "maxLength": 255 + } + ] + }, + "created_on": { + "description": "Date and time of creation", + "format": "date-time", + "readOnly": true, + "type": "string" + }, + "modified_on": { + "description": "Date and time of last update", + "format": "date-time", + "readOnly": true, + "type": "string" + }, + "user_id": { + "description": "User ID", + "example": 1234, + "type": "integer", + "minimum": 1 + }, + "certificate_id": { + "description": "Certificate ID", + "example": 1234, + "anyOf": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "string", + "pattern": "^new$" + } + ] + }, + "access_list_id": { + "description": "Access List ID", + "example": 1234, + "type": "integer", + "minimum": 0 + }, + "domain_names": { + "description": "Domain Names separated by a comma", + "example": "*.jc21.com,blog.jc21.com", + "type": "array", + "minItems": 1, + "maxItems": 100, + "uniqueItems": true, + "items": { + "type": "string", + "pattern": "^(?:\\*\\.)?(?:[^.*]+\\.?)+[^.]$" + } + }, + "enabled": { + "description": "Is Enabled", + "example": true, + "type": "boolean" + }, + "ssl_forced": { + "description": "Is SSL Forced", + "example": false, + "type": "boolean" + }, + "hsts_enabled": { + "description": "Is HSTS Enabled", + "example": false, + "type": "boolean" + }, + "hsts_subdomains": { + "description": "Is HSTS applicable to all subdomains", + "example": false, + "type": "boolean" + }, + "ssl_provider": { + "type": "string", + "pattern": "^(letsencrypt|other)$" + }, + "http2_support": { + "description": "HTTP2 Protocol Support", + "example": false, + "type": "boolean" + }, + "block_exploits": { + "description": "Should we block common exploits", + "example": true, + "type": "boolean" + }, + "caching_enabled": { + "description": "Should we cache assets", + "example": true, + "type": "boolean" + } + } +} diff --git a/backend/schema/components/access-list-object.json b/backend/schema/components/access-list-object.json new file mode 100644 index 000000000..c6ed51a58 --- /dev/null +++ b/backend/schema/components/access-list-object.json @@ -0,0 +1,53 @@ +{ + "type": "object", + "description": "Access List object", + "required": ["id", "created_on", "modified_on", "owner_user_id", "name", "directive", "address", "satisfy_any", "pass_auth", "meta"], + "additionalProperties": false, + "properties": { + "id": { + "$ref": "../common.json#/definitions/id" + }, + "created_on": { + "$ref": "../common.json#/definitions/created_on" + }, + "modified_on": { + "$ref": "../common.json#/definitions/modified_on" + }, + "owner_user_id": { + "$ref": "../common.json#/definitions/user_id" + }, + "name": { + "type": "string", + "minLength": 1 + }, + "directive": { + "type": "string", + "enum": ["allow", "deny"] + }, + "address": { + "oneOf": [ + { + "type": "string", + "pattern": "^([0-9]{1,3}\\.){3}[0-9]{1,3}(/([0-9]|[1-2][0-9]|3[0-2]))?$" + }, + { + "type": "string", + "pattern": "^s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:)))(%.+)?s*(/([0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8]))?$" + }, + { + "type": "string", + "pattern": "^all$" + } + ] + }, + "satisfy_any": { + "type": "boolean" + }, + "pass_auth": { + "type": "boolean" + }, + "meta": { + "type": "object" + } + } +} diff --git a/backend/schema/components/audit-log-object.json b/backend/schema/components/audit-log-object.json new file mode 100644 index 000000000..f38606e12 --- /dev/null +++ b/backend/schema/components/audit-log-object.json @@ -0,0 +1,32 @@ +{ + "type": "object", + "description": "Audit Log object", + "required": ["id", "created_on", "modified_on", "user_id", "object_type", "object_id", "action", "meta"], + "additionalProperties": false, + "properties": { + "id": { + "$ref": "../common.json#/definitions/id" + }, + "created_on": { + "$ref": "../common.json#/definitions/created_on" + }, + "modified_on": { + "$ref": "../common.json#/definitions/modified_on" + }, + "user_id": { + "$ref": "../common.json#/definitions/user_id" + }, + "object_type": { + "type": "string" + }, + "object_id": { + "$ref": "../common.json#/definitions/id" + }, + "action": { + "type": "string" + }, + "meta": { + "type": "object" + } + } +} diff --git a/backend/schema/components/certificate-list.json b/backend/schema/components/certificate-list.json new file mode 100644 index 000000000..cec4db82c --- /dev/null +++ b/backend/schema/components/certificate-list.json @@ -0,0 +1,7 @@ +{ + "type": "array", + "description": "Certificates list", + "items": { + "$ref": "./certificate-object.json" + } +} diff --git a/backend/schema/components/certificate-object.json b/backend/schema/components/certificate-object.json new file mode 100644 index 000000000..8e6a28523 --- /dev/null +++ b/backend/schema/components/certificate-object.json @@ -0,0 +1,66 @@ +{ + "type": "object", + "description": "Certificate object", + "required": ["id", "created_on", "modified_on", "owner_user_id", "provider", "nice_name", "domain_names", "expires_on", "meta"], + "additionalProperties": false, + "properties": { + "id": { + "$ref": "../common.json#/definitions/id" + }, + "created_on": { + "$ref": "../common.json#/definitions/created_on" + }, + "modified_on": { + "$ref": "../common.json#/definitions/modified_on" + }, + "owner_user_id": { + "$ref": "../common.json#/definitions/user_id" + }, + "provider": { + "$ref": "../common.json#/definitions/ssl_provider" + }, + "nice_name": { + "type": "string", + "description": "Nice Name for the custom certificate" + }, + "domain_names": { + "$ref": "../common.json#/definitions/domain_names" + }, + "expires_on": { + "description": "Date and time of expiration", + "format": "date-time", + "readOnly": true, + "type": "string" + }, + "meta": { + "type": "object", + "additionalProperties": false, + "properties": { + "letsencrypt_email": { + "type": "string", + "format": "email" + }, + "letsencrypt_agree": { + "type": "boolean" + }, + "dns_challenge": { + "type": "boolean" + }, + "dns_provider": { + "type": "string" + }, + "dns_provider_credentials": { + "type": "string" + }, + "propagation_seconds": { + "anyOf": [ + { + "type": "integer", + "minimum": 0 + } + ] + } + } + } + } +} diff --git a/backend/schema/components/dead-host-list.json b/backend/schema/components/dead-host-list.json new file mode 100644 index 000000000..56ff303ba --- /dev/null +++ b/backend/schema/components/dead-host-list.json @@ -0,0 +1,7 @@ +{ + "type": "array", + "description": "404 Hosts list", + "items": { + "$ref": "./dead-host-object.json" + } +} diff --git a/backend/schema/components/dead-host-object.json b/backend/schema/components/dead-host-object.json new file mode 100644 index 000000000..84ad17793 --- /dev/null +++ b/backend/schema/components/dead-host-object.json @@ -0,0 +1,47 @@ +{ + "type": "object", + "description": "404 Host object", + "required": ["id", "created_on", "modified_on", "owner_user_id", "domain_names", "certificate_id", "ssl_forced", "hsts_enabled", "hsts_subdomains", "http2_support", "advanced_config", "enabled", "meta"], + "additionalProperties": false, + "properties": { + "id": { + "$ref": "../common.json#/definitions/id" + }, + "created_on": { + "$ref": "../common.json#/definitions/created_on" + }, + "modified_on": { + "$ref": "../common.json#/definitions/modified_on" + }, + "owner_user_id": { + "$ref": "../common.json#/definitions/user_id" + }, + "domain_names": { + "$ref": "../common.json#/definitions/domain_names" + }, + "certificate_id": { + "$ref": "../common.json#/definitions/certificate_id" + }, + "ssl_forced": { + "$ref": "../common.json#/definitions/ssl_forced" + }, + "hsts_enabled": { + "$ref": "../common.json#/definitions/hsts_enabled" + }, + "hsts_subdomains": { + "$ref": "../common.json#/definitions/hsts_subdomains" + }, + "http2_support": { + "$ref": "../common.json#/definitions/http2_support" + }, + "advanced_config": { + "type": "string" + }, + "enabled": { + "$ref": "../common.json#/definitions/enabled" + }, + "meta": { + "type": "object" + } + } +} diff --git a/backend/schema/components/error-object.json b/backend/schema/components/error-object.json new file mode 100644 index 000000000..c2540cf1f --- /dev/null +++ b/backend/schema/components/error-object.json @@ -0,0 +1,14 @@ +{ + "type": "object", + "description": "Error object", + "additionalProperties": false, + "required": ["code", "message"], + "properties": { + "code": { + "type": "integer" + }, + "message": { + "type": "string" + } + } +} diff --git a/backend/schema/components/health-object.json b/backend/schema/components/health-object.json new file mode 100644 index 000000000..8d223417b --- /dev/null +++ b/backend/schema/components/health-object.json @@ -0,0 +1,38 @@ +{ + "type": "object", + "description": "Health object", + "additionalProperties": false, + "required": ["status", "version"], + "properties": { + "status": { + "type": "string", + "description": "Healthy", + "example": "OK" + }, + "version": { + "type": "object", + "description": "The version object", + "example": { + "major": 2, + "minor": 0, + "revision": 0 + }, + "additionalProperties": false, + "required": ["major", "minor", "revision"], + "properties": { + "major": { + "type": "integer", + "minimum": 0 + }, + "minor": { + "type": "integer", + "minimum": 0 + }, + "revision": { + "type": "integer", + "minimum": 0 + } + } + } + } +} diff --git a/backend/schema/components/permission-object.json b/backend/schema/components/permission-object.json new file mode 100644 index 000000000..b852a014d --- /dev/null +++ b/backend/schema/components/permission-object.json @@ -0,0 +1,41 @@ +{ + "type": "object", + "minProperties": 1, + "properties": { + "visibility": { + "type": "string", + "description": "Visibility Type", + "enum": ["all", "user"] + }, + "access_lists": { + "type": "string", + "description": "Access Lists Permissions", + "enum": ["hidden", "view", "manage"] + }, + "dead_hosts": { + "type": "string", + "description": "404 Hosts Permissions", + "enum": ["hidden", "view", "manage"] + }, + "proxy_hosts": { + "type": "string", + "description": "Proxy Hosts Permissions", + "enum": ["hidden", "view", "manage"] + }, + "redirection_hosts": { + "type": "string", + "description": "Redirection Permissions", + "enum": ["hidden", "view", "manage"] + }, + "streams": { + "type": "string", + "description": "Streams Permissions", + "enum": ["hidden", "view", "manage"] + }, + "certificates": { + "type": "string", + "description": "Certificates Permissions", + "enum": ["hidden", "view", "manage"] + } + } +} diff --git a/backend/schema/components/proxy-host-list.json b/backend/schema/components/proxy-host-list.json new file mode 100644 index 000000000..39789b4a7 --- /dev/null +++ b/backend/schema/components/proxy-host-list.json @@ -0,0 +1,7 @@ +{ + "type": "array", + "description": "Proxy Hosts list", + "items": { + "$ref": "./proxy-host-object.json" + } +} diff --git a/backend/schema/components/proxy-host-object.json b/backend/schema/components/proxy-host-object.json new file mode 100644 index 000000000..18414bd4c --- /dev/null +++ b/backend/schema/components/proxy-host-object.json @@ -0,0 +1,148 @@ +{ + "type": "object", + "description": "Proxy Host object", + "required": [ + "id", + "created_on", + "modified_on", + "owner_user_id", + "domain_names", + "forward_host", + "forward_port", + "access_list_id", + "certificate_id", + "ssl_forced", + "caching_enabled", + "block_exploits", + "advanced_config", + "meta", + "allow_websocket_upgrade", + "http2_support", + "forward_scheme", + "enabled", + "locations", + "hsts_enabled", + "hsts_subdomains", + "certificate", + "use_default_location", + "ipv6" + ], + "additionalProperties": false, + "properties": { + "id": { + "$ref": "../common.json#/definitions/id" + }, + "created_on": { + "$ref": "../common.json#/definitions/created_on" + }, + "modified_on": { + "$ref": "../common.json#/definitions/modified_on" + }, + "owner_user_id": { + "$ref": "../common.json#/definitions/user_id" + }, + "domain_names": { + "$ref": "../common.json#/definitions/domain_names" + }, + "forward_host": { + "type": "string", + "minLength": 1, + "maxLength": 255 + }, + "forward_port": { + "type": "integer", + "minimum": 1, + "maximum": 65535 + }, + "access_list_id": { + "$ref": "../common.json#/definitions/access_list_id" + }, + "certificate_id": { + "$ref": "../common.json#/definitions/certificate_id" + }, + "ssl_forced": { + "$ref": "../common.json#/definitions/ssl_forced" + }, + "caching_enabled": { + "$ref": "../common.json#/definitions/caching_enabled" + }, + "block_exploits": { + "$ref": "../common.json#/definitions/block_exploits" + }, + "advanced_config": { + "type": "string" + }, + "meta": { + "type": "object" + }, + "allow_websocket_upgrade": { + "description": "Allow Websocket Upgrade for all paths", + "example": true, + "type": "boolean" + }, + "http2_support": { + "$ref": "../common.json#/definitions/http2_support" + }, + "forward_scheme": { + "type": "string", + "enum": ["http", "https"] + }, + "enabled": { + "$ref": "../common.json#/definitions/enabled" + }, + "locations": { + "type": "array", + "minItems": 0, + "items": { + "type": "object", + "required": ["forward_scheme", "forward_host", "forward_port", "path"], + "additionalProperties": false, + "properties": { + "id": { + "type": ["integer", "null"] + }, + "path": { + "type": "string", + "minLength": 1 + }, + "forward_scheme": { + "$ref": "#/properties/forward_scheme" + }, + "forward_host": { + "$ref": "#/properties/forward_host" + }, + "forward_port": { + "$ref": "#/properties/forward_port" + }, + "forward_path": { + "type": "string" + }, + "advanced_config": { + "type": "string" + } + } + } + }, + "hsts_enabled": { + "$ref": "../common.json#/definitions/hsts_enabled" + }, + "hsts_subdomains": { + "$ref": "../common.json#/definitions/hsts_subdomains" + }, + "certificate": { + "$ref": "./certificate-object.json" + }, + "owner": { + "$ref": "./user-object.json" + }, + "access_list": { + "$ref": "./access-list-object.json" + }, + "use_default_location": { + "type": "boolean" + }, + "ipv6": { + "type": "boolean" + } + } +} diff --git a/backend/schema/components/redirection-host-list.json b/backend/schema/components/redirection-host-list.json new file mode 100644 index 000000000..716dcfa1d --- /dev/null +++ b/backend/schema/components/redirection-host-list.json @@ -0,0 +1,7 @@ +{ + "type": "array", + "description": "Redirection Hosts list", + "items": { + "$ref": "./redirection-host-object.json" + } +} diff --git a/backend/schema/components/redirection-host-object.json b/backend/schema/components/redirection-host-object.json new file mode 100644 index 000000000..080b75e59 --- /dev/null +++ b/backend/schema/components/redirection-host-object.json @@ -0,0 +1,72 @@ +{ + "type": "object", + "description": "Redirection Host object", + "required": ["id", "created_on", "modified_on", "owner_user_id", "domain_names", "forward_http_code", "forward_scheme", "forward_domain_name", "preserve_path", "certificate_id", "ssl_forced", "hsts_enabled", "hsts_subdomains", "http2_support", "block_exploits", "advanced_config", "enabled", "meta"], + "additionalProperties": false, + "properties": { + "id": { + "$ref": "../common.json#/definitions/id" + }, + "created_on": { + "$ref": "../common.json#/definitions/created_on" + }, + "modified_on": { + "$ref": "../common.json#/definitions/modified_on" + }, + "owner_user_id": { + "$ref": "../common.json#/definitions/user_id" + }, + "domain_names": { + "$ref": "../common.json#/definitions/domain_names" + }, + "forward_http_code": { + "description": "Redirect HTTP Status Code", + "example": 302, + "type": "integer", + "minimum": 300, + "maximum": 308 + }, + "forward_scheme": { + "type": "string", + "enum": ["http", "https"] + }, + "forward_domain_name": { + "description": "Domain Name", + "example": "jc21.com", + "type": "string", + "pattern": "^(?:[^.*]+\\.?)+[^.]$" + }, + "preserve_path": { + "description": "Should the path be preserved", + "example": true, + "type": "boolean" + }, + "certificate_id": { + "$ref": "../common.json#/definitions/certificate_id" + }, + "ssl_forced": { + "$ref": "../common.json#/definitions/ssl_forced" + }, + "hsts_enabled": { + "$ref": "../common.json#/definitions/hsts_enabled" + }, + "hsts_subdomains": { + "$ref": "../common.json#/definitions/hsts_subdomains" + }, + "http2_support": { + "$ref": "../common.json#/definitions/http2_support" + }, + "block_exploits": { + "$ref": "../common.json#/definitions/block_exploits" + }, + "advanced_config": { + "type": "string" + }, + "enabled": { + "$ref": "../common.json#/definitions/enabled" + }, + "meta": { + "type": "object" + } + } +} diff --git a/backend/schema/components/security-schemes.json b/backend/schema/components/security-schemes.json new file mode 100644 index 000000000..82407be3f --- /dev/null +++ b/backend/schema/components/security-schemes.json @@ -0,0 +1,6 @@ +{ + "BearerAuth": { + "type": "http", + "scheme": "bearer" + } +} diff --git a/backend/schema/components/setting-list.json b/backend/schema/components/setting-list.json new file mode 100644 index 000000000..c66f099ea --- /dev/null +++ b/backend/schema/components/setting-list.json @@ -0,0 +1,7 @@ +{ + "type": "array", + "description": "Setting list", + "items": { + "$ref": "./setting-object.json" + } +} diff --git a/backend/schema/components/setting-object.json b/backend/schema/components/setting-object.json new file mode 100644 index 000000000..e08777264 --- /dev/null +++ b/backend/schema/components/setting-object.json @@ -0,0 +1,53 @@ +{ + "type": "object", + "description": "Setting object", + "required": ["id", "name", "description", "value", "meta"], + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "description": "Setting ID", + "minLength": 1, + "example": "default-site" + }, + "name": { + "type": "string", + "description": "Setting Display Name", + "minLength": 1, + "example": "Default Site" + }, + "description": { + "type": "string", + "description": "Meaningful description", + "minLength": 1, + "example": "What to show when Nginx is hit with an unknown Host" + }, + "value": { + "description": "Value in almost any form", + "example": "congratulations", + "oneOf": [ + { + "type": "string", + "minLength": 1 + }, + { + "type": "integer" + }, + { + "type": "object" + }, + { + "type": "number" + }, + { + "type": "array" + } + ] + }, + "meta": { + "description": "Extra metadata", + "example": {}, + "type": "object" + } + } +} diff --git a/backend/schema/components/stream-list.json b/backend/schema/components/stream-list.json new file mode 100644 index 000000000..39789b4a7 --- /dev/null +++ b/backend/schema/components/stream-list.json @@ -0,0 +1,7 @@ +{ + "type": "array", + "description": "Proxy Hosts list", + "items": { + "$ref": "./proxy-host-object.json" + } +} diff --git a/backend/schema/components/stream-object.json b/backend/schema/components/stream-object.json new file mode 100644 index 000000000..9b92d26dd --- /dev/null +++ b/backend/schema/components/stream-object.json @@ -0,0 +1,60 @@ +{ + "type": "object", + "description": "Stream object", + "required": ["id", "created_on", "modified_on", "owner_user_id", "incoming_port", "forwarding_host", "forwarding_port", "tcp_forwarding", "udp_forwarding", "enabled", "meta"], + "additionalProperties": false, + "properties": { + "id": { + "$ref": "../common.json#/definitions/id" + }, + "created_on": { + "$ref": "../common.json#/definitions/created_on" + }, + "modified_on": { + "$ref": "../common.json#/definitions/modified_on" + }, + "owner_user_id": { + "$ref": "../common.json#/definitions/user_id" + }, + "incoming_port": { + "type": "integer", + "minimum": 1, + "maximum": 65535 + }, + "forwarding_host": { + "anyOf": [ + { + "description": "Domain Name", + "example": "jc21.com", + "type": "string", + "pattern": "^(?:[^.*]+\\.?)+[^.]$" + }, + { + "type": "string", + "format": "ipv4" + }, + { + "type": "string", + "format": "ipv6" + } + ] + }, + "forwarding_port": { + "type": "integer", + "minimum": 1, + "maximum": 65535 + }, + "tcp_forwarding": { + "type": "boolean" + }, + "udp_forwarding": { + "type": "boolean" + }, + "enabled": { + "$ref": "../common.json#/definitions/enabled" + }, + "meta": { + "type": "object" + } + } +} diff --git a/backend/schema/components/token-object.json b/backend/schema/components/token-object.json new file mode 100644 index 000000000..a7044bce9 --- /dev/null +++ b/backend/schema/components/token-object.json @@ -0,0 +1,19 @@ +{ + "type": "object", + "description": "Token object", + "required": ["expires", "token"], + "additionalProperties": false, + "properties": { + "expires": { + "description": "Token Expiry Unix Time", + "example": 1566540249, + "minimum": 1, + "type": "number" + }, + "token": { + "description": "JWT Token", + "example": "eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.ey...xaHKYr3Kk6MvkUjcC4", + "type": "string" + } + } +} diff --git a/backend/schema/components/user-list.json b/backend/schema/components/user-list.json new file mode 100644 index 000000000..c5c0f7116 --- /dev/null +++ b/backend/schema/components/user-list.json @@ -0,0 +1,7 @@ +{ + "type": "array", + "description": "User list", + "items": { + "$ref": "./user-object.json" + } +} diff --git a/backend/schema/components/user-object.json b/backend/schema/components/user-object.json new file mode 100644 index 000000000..7f01a6ac8 --- /dev/null +++ b/backend/schema/components/user-object.json @@ -0,0 +1,61 @@ +{ + "type": "object", + "description": "User object", + "required": ["id", "created_on", "modified_on", "is_disabled", "email", "name", "nickname", "avatar", "roles"], + "additionalProperties": false, + "properties": { + "id": { + "type": "integer", + "description": "User ID", + "minimum": 1, + "example": 1 + }, + "created_on": { + "type": "string", + "description": "Created Date", + "example": "2020-01-30T09:36:08.000Z" + }, + "modified_on": { + "type": "string", + "description": "Modified Date", + "example": "2020-01-30T09:41:04.000Z" + }, + "is_disabled": { + "type": "integer", + "minimum": 0, + "maximum": 1, + "description": "Is user Disabled (0 = false, 1 = true)", + "example": 0 + }, + "email": { + "type": "string", + "description": "Email", + "minLength": 3, + "example": "jc@jc21.com" + }, + "name": { + "type": "string", + "description": "Name", + "minLength": 1, + "example": "Jamie Curnow" + }, + "nickname": { + "type": "string", + "description": "Nickname", + "example": "James" + }, + "avatar": { + "type": "string", + "description": "Gravatar URL based on email, without scheme", + "example": "//www.gravatar.com/avatar/6193176330f8d38747f038c170ddb193?default=mm" + }, + "roles": { + "description": "Roles applied", + "example": ["admin"], + "type": "array", + "items": { + "type": "string" + } + } + } +} diff --git a/backend/schema/definitions.json b/backend/schema/definitions.json deleted file mode 100644 index 640093a08..000000000 --- a/backend/schema/definitions.json +++ /dev/null @@ -1,240 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "definitions", - "definitions": { - "id": { - "description": "Unique identifier", - "example": 123456, - "readOnly": true, - "type": "integer", - "minimum": 1 - }, - "setting_id": { - "description": "Unique identifier for a Setting", - "example": "default-site", - "readOnly": true, - "type": "string", - "minLength": 2 - }, - "token": { - "type": "string", - "minLength": 10 - }, - "expand": { - "anyOf": [ - { - "type": "null" - }, - { - "type": "array", - "minItems": 1, - "items": { - "type": "string" - } - } - ] - }, - "sort": { - "type": "array", - "minItems": 1, - "items": { - "type": "object", - "required": [ - "field", - "dir" - ], - "additionalProperties": false, - "properties": { - "field": { - "type": "string" - }, - "dir": { - "type": "string", - "pattern": "^(asc|desc)$" - } - } - } - }, - "query": { - "anyOf": [ - { - "type": "null" - }, - { - "type": "string", - "minLength": 1, - "maxLength": 255 - } - ] - }, - "criteria": { - "anyOf": [ - { - "type": "null" - }, - { - "type": "object" - } - ] - }, - "fields": { - "anyOf": [ - { - "type": "null" - }, - { - "type": "array", - "minItems": 1, - "items": { - "type": "string" - } - } - ] - }, - "omit": { - "anyOf": [ - { - "type": "null" - }, - { - "type": "array", - "minItems": 1, - "items": { - "type": "string" - } - } - ] - }, - "created_on": { - "description": "Date and time of creation", - "format": "date-time", - "readOnly": true, - "type": "string" - }, - "modified_on": { - "description": "Date and time of last update", - "format": "date-time", - "readOnly": true, - "type": "string" - }, - "user_id": { - "description": "User ID", - "example": 1234, - "type": "integer", - "minimum": 1 - }, - "certificate_id": { - "description": "Certificate ID", - "example": 1234, - "anyOf": [ - { - "type": "integer", - "minimum": 0 - }, - { - "type": "string", - "pattern": "^new$" - } - ] - }, - "access_list_id": { - "description": "Access List ID", - "example": 1234, - "type": "integer", - "minimum": 0 - }, - "name": { - "type": "string", - "minLength": 1, - "maxLength": 255 - }, - "email": { - "description": "Email Address", - "example": "john@example.com", - "format": "email", - "type": "string", - "minLength": 6, - "maxLength": 100 - }, - "password": { - "description": "Password", - "type": "string", - "minLength": 8, - "maxLength": 255 - }, - "domain_name": { - "description": "Domain Name", - "example": "jc21.com", - "type": "string", - "pattern": "^(?:[^.*]+\\.?)+[^.]$" - }, - "domain_names": { - "description": "Domain Names separated by a comma", - "example": "*.jc21.com,blog.jc21.com", - "type": "array", - "maxItems": 100, - "uniqueItems": true, - "items": { - "type": "string", - "pattern": "^(?:\\*\\.)?(?:[^.*]+\\.?)+[^.]$" - } - }, - "http_code": { - "description": "Redirect HTTP Status Code", - "example": 302, - "type": "integer", - "minimum": 300, - "maximum": 308 - }, - "scheme": { - "description": "RFC Protocol", - "example": "HTTPS or $scheme", - "type": "string", - "minLength": 4 - }, - "enabled": { - "description": "Is Enabled", - "example": true, - "type": "boolean" - }, - "ssl_enabled": { - "description": "Is SSL Enabled", - "example": true, - "type": "boolean" - }, - "ssl_forced": { - "description": "Is SSL Forced", - "example": false, - "type": "boolean" - }, - "hsts_enabled": { - "description": "Is HSTS Enabled", - "example": false, - "type": "boolean" - }, - "hsts_subdomains": { - "description": "Is HSTS applicable to all subdomains", - "example": false, - "type": "boolean" - }, - "ssl_provider": { - "type": "string", - "pattern": "^(letsencrypt|other)$" - }, - "http2_support": { - "description": "HTTP2 Protocol Support", - "example": false, - "type": "boolean" - }, - "block_exploits": { - "description": "Should we block common exploits", - "example": true, - "type": "boolean" - }, - "caching_enabled": { - "description": "Should we cache assets", - "example": true, - "type": "boolean" - } - } -} diff --git a/backend/schema/endpoints/access-lists.json b/backend/schema/endpoints/access-lists.json deleted file mode 100644 index 404e32376..000000000 --- a/backend/schema/endpoints/access-lists.json +++ /dev/null @@ -1,236 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "endpoints/access-lists", - "title": "Access Lists", - "description": "Endpoints relating to Access Lists", - "stability": "stable", - "type": "object", - "definitions": { - "id": { - "$ref": "../definitions.json#/definitions/id" - }, - "created_on": { - "$ref": "../definitions.json#/definitions/created_on" - }, - "modified_on": { - "$ref": "../definitions.json#/definitions/modified_on" - }, - "name": { - "type": "string", - "description": "Name of the Access List" - }, - "directive": { - "type": "string", - "enum": ["allow", "deny"] - }, - "address": { - "oneOf": [ - { - "type": "string", - "pattern": "^([0-9]{1,3}\\.){3}[0-9]{1,3}(/([0-9]|[1-2][0-9]|3[0-2]))?$" - }, - { - "type": "string", - "pattern": "^s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:)))(%.+)?s*(/([0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8]))?$" - }, - { - "type": "string", - "pattern": "^all$" - } - ] - }, - "satisfy_any": { - "type": "boolean" - }, - "pass_auth": { - "type": "boolean" - }, - "meta": { - "type": "object" - } - }, - "properties": { - "id": { - "$ref": "#/definitions/id" - }, - "created_on": { - "$ref": "#/definitions/created_on" - }, - "modified_on": { - "$ref": "#/definitions/modified_on" - }, - "name": { - "$ref": "#/definitions/name" - }, - "meta": { - "$ref": "#/definitions/meta" - } - }, - "links": [ - { - "title": "List", - "description": "Returns a list of Access Lists", - "href": "/nginx/access-lists", - "access": "private", - "method": "GET", - "rel": "self", - "http_header": { - "$ref": "../examples.json#/definitions/auth_header" - }, - "targetSchema": { - "type": "array", - "items": { - "$ref": "#/properties" - } - } - }, - { - "title": "Create", - "description": "Creates a new Access List", - "href": "/nginx/access-list", - "access": "private", - "method": "POST", - "rel": "create", - "http_header": { - "$ref": "../examples.json#/definitions/auth_header" - }, - "schema": { - "type": "object", - "additionalProperties": false, - "required": ["name"], - "properties": { - "name": { - "$ref": "#/definitions/name" - }, - "satisfy_any": { - "$ref": "#/definitions/satisfy_any" - }, - "pass_auth": { - "$ref": "#/definitions/pass_auth" - }, - "items": { - "type": "array", - "minItems": 0, - "items": { - "type": "object", - "additionalProperties": false, - "properties": { - "username": { - "type": "string", - "minLength": 1 - }, - "password": { - "type": "string", - "minLength": 1 - } - } - } - }, - "clients": { - "type": "array", - "minItems": 0, - "items": { - "type": "object", - "additionalProperties": false, - "properties": { - "address": { - "$ref": "#/definitions/address" - }, - "directive": { - "$ref": "#/definitions/directive" - } - } - } - }, - "meta": { - "$ref": "#/definitions/meta" - } - } - }, - "targetSchema": { - "properties": { - "$ref": "#/properties" - } - } - }, - { - "title": "Update", - "description": "Updates a existing Access List", - "href": "/nginx/access-list/{definitions.identity.example}", - "access": "private", - "method": "PUT", - "rel": "update", - "http_header": { - "$ref": "../examples.json#/definitions/auth_header" - }, - "schema": { - "type": "object", - "additionalProperties": false, - "properties": { - "name": { - "$ref": "#/definitions/name" - }, - "satisfy_any": { - "$ref": "#/definitions/satisfy_any" - }, - "pass_auth": { - "$ref": "#/definitions/pass_auth" - }, - "items": { - "type": "array", - "minItems": 0, - "items": { - "type": "object", - "additionalProperties": false, - "properties": { - "username": { - "type": "string", - "minLength": 1 - }, - "password": { - "type": "string", - "minLength": 0 - } - } - } - }, - "clients": { - "type": "array", - "minItems": 0, - "items": { - "type": "object", - "additionalProperties": false, - "properties": { - "address": { - "$ref": "#/definitions/address" - }, - "directive": { - "$ref": "#/definitions/directive" - } - } - } - } - } - }, - "targetSchema": { - "properties": { - "$ref": "#/properties" - } - } - }, - { - "title": "Delete", - "description": "Deletes a existing Access List", - "href": "/nginx/access-list/{definitions.identity.example}", - "access": "private", - "method": "DELETE", - "rel": "delete", - "http_header": { - "$ref": "../examples.json#/definitions/auth_header" - }, - "targetSchema": { - "type": "boolean" - } - } - ] -} diff --git a/backend/schema/endpoints/certificates.json b/backend/schema/endpoints/certificates.json deleted file mode 100644 index 955ca75c9..000000000 --- a/backend/schema/endpoints/certificates.json +++ /dev/null @@ -1,173 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "endpoints/certificates", - "title": "Certificates", - "description": "Endpoints relating to Certificates", - "stability": "stable", - "type": "object", - "definitions": { - "id": { - "$ref": "../definitions.json#/definitions/id" - }, - "created_on": { - "$ref": "../definitions.json#/definitions/created_on" - }, - "modified_on": { - "$ref": "../definitions.json#/definitions/modified_on" - }, - "provider": { - "$ref": "../definitions.json#/definitions/ssl_provider" - }, - "nice_name": { - "type": "string", - "description": "Nice Name for the custom certificate" - }, - "domain_names": { - "$ref": "../definitions.json#/definitions/domain_names" - }, - "expires_on": { - "description": "Date and time of expiration", - "format": "date-time", - "readOnly": true, - "type": "string" - }, - "meta": { - "type": "object", - "additionalProperties": false, - "properties": { - "letsencrypt_email": { - "type": "string", - "format": "email" - }, - "letsencrypt_agree": { - "type": "boolean" - }, - "dns_challenge": { - "type": "boolean" - }, - "dns_provider": { - "type": "string" - }, - "dns_provider_credentials": { - "type": "string" - }, - "propagation_seconds": { - "anyOf": [ - { - "type": "integer", - "minimum": 0 - } - ] - - } - } - } - }, - "properties": { - "id": { - "$ref": "#/definitions/id" - }, - "created_on": { - "$ref": "#/definitions/created_on" - }, - "modified_on": { - "$ref": "#/definitions/modified_on" - }, - "provider": { - "$ref": "#/definitions/provider" - }, - "nice_name": { - "$ref": "#/definitions/nice_name" - }, - "domain_names": { - "$ref": "#/definitions/domain_names" - }, - "expires_on": { - "$ref": "#/definitions/expires_on" - }, - "meta": { - "$ref": "#/definitions/meta" - } - }, - "links": [ - { - "title": "List", - "description": "Returns a list of Certificates", - "href": "/nginx/certificates", - "access": "private", - "method": "GET", - "rel": "self", - "http_header": { - "$ref": "../examples.json#/definitions/auth_header" - }, - "targetSchema": { - "type": "array", - "items": { - "$ref": "#/properties" - } - } - }, - { - "title": "Create", - "description": "Creates a new Certificate", - "href": "/nginx/certificates", - "access": "private", - "method": "POST", - "rel": "create", - "http_header": { - "$ref": "../examples.json#/definitions/auth_header" - }, - "schema": { - "type": "object", - "additionalProperties": false, - "required": [ - "provider" - ], - "properties": { - "provider": { - "$ref": "#/definitions/provider" - }, - "nice_name": { - "$ref": "#/definitions/nice_name" - }, - "domain_names": { - "$ref": "#/definitions/domain_names" - }, - "meta": { - "$ref": "#/definitions/meta" - } - } - }, - "targetSchema": { - "properties": { - "$ref": "#/properties" - } - } - }, - { - "title": "Delete", - "description": "Deletes a existing Certificate", - "href": "/nginx/certificates/{definitions.identity.example}", - "access": "private", - "method": "DELETE", - "rel": "delete", - "http_header": { - "$ref": "../examples.json#/definitions/auth_header" - }, - "targetSchema": { - "type": "boolean" - } - }, - { - "title": "Test HTTP Challenge", - "description": "Tests whether the HTTP challenge should work", - "href": "/nginx/certificates/{definitions.identity.example}/test-http", - "access": "private", - "method": "GET", - "rel": "info", - "http_header": { - "$ref": "../examples.json#/definitions/auth_header" - } - } - ] -} diff --git a/backend/schema/endpoints/dead-hosts.json b/backend/schema/endpoints/dead-hosts.json deleted file mode 100644 index 0c73c3be1..000000000 --- a/backend/schema/endpoints/dead-hosts.json +++ /dev/null @@ -1,240 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "endpoints/dead-hosts", - "title": "404 Hosts", - "description": "Endpoints relating to 404 Hosts", - "stability": "stable", - "type": "object", - "definitions": { - "id": { - "$ref": "../definitions.json#/definitions/id" - }, - "created_on": { - "$ref": "../definitions.json#/definitions/created_on" - }, - "modified_on": { - "$ref": "../definitions.json#/definitions/modified_on" - }, - "domain_names": { - "$ref": "../definitions.json#/definitions/domain_names" - }, - "certificate_id": { - "$ref": "../definitions.json#/definitions/certificate_id" - }, - "ssl_forced": { - "$ref": "../definitions.json#/definitions/ssl_forced" - }, - "hsts_enabled": { - "$ref": "../definitions.json#/definitions/hsts_enabled" - }, - "hsts_subdomains": { - "$ref": "../definitions.json#/definitions/hsts_subdomains" - }, - "http2_support": { - "$ref": "../definitions.json#/definitions/http2_support" - }, - "advanced_config": { - "type": "string" - }, - "enabled": { - "$ref": "../definitions.json#/definitions/enabled" - }, - "meta": { - "type": "object" - } - }, - "properties": { - "id": { - "$ref": "#/definitions/id" - }, - "created_on": { - "$ref": "#/definitions/created_on" - }, - "modified_on": { - "$ref": "#/definitions/modified_on" - }, - "domain_names": { - "$ref": "#/definitions/domain_names" - }, - "certificate_id": { - "$ref": "#/definitions/certificate_id" - }, - "ssl_forced": { - "$ref": "#/definitions/ssl_forced" - }, - "hsts_enabled": { - "$ref": "#/definitions/hsts_enabled" - }, - "hsts_subdomains": { - "$ref": "#/definitions/hsts_subdomains" - }, - "http2_support": { - "$ref": "#/definitions/http2_support" - }, - "advanced_config": { - "$ref": "#/definitions/advanced_config" - }, - "enabled": { - "$ref": "#/definitions/enabled" - }, - "meta": { - "$ref": "#/definitions/meta" - } - }, - "links": [ - { - "title": "List", - "description": "Returns a list of 404 Hosts", - "href": "/nginx/dead-hosts", - "access": "private", - "method": "GET", - "rel": "self", - "http_header": { - "$ref": "../examples.json#/definitions/auth_header" - }, - "targetSchema": { - "type": "array", - "items": { - "$ref": "#/properties" - } - } - }, - { - "title": "Create", - "description": "Creates a new 404 Host", - "href": "/nginx/dead-hosts", - "access": "private", - "method": "POST", - "rel": "create", - "http_header": { - "$ref": "../examples.json#/definitions/auth_header" - }, - "schema": { - "type": "object", - "additionalProperties": false, - "required": [ - "domain_names" - ], - "properties": { - "domain_names": { - "$ref": "#/definitions/domain_names" - }, - "certificate_id": { - "$ref": "#/definitions/certificate_id" - }, - "ssl_forced": { - "$ref": "#/definitions/ssl_forced" - }, - "hsts_enabled": { - "$ref": "#/definitions/hsts_enabled" - }, - "hsts_subdomains": { - "$ref": "#/definitions/hsts_enabled" - }, - "http2_support": { - "$ref": "#/definitions/http2_support" - }, - "advanced_config": { - "$ref": "#/definitions/advanced_config" - }, - "meta": { - "$ref": "#/definitions/meta" - } - } - }, - "targetSchema": { - "properties": { - "$ref": "#/properties" - } - } - }, - { - "title": "Update", - "description": "Updates a existing 404 Host", - "href": "/nginx/dead-hosts/{definitions.identity.example}", - "access": "private", - "method": "PUT", - "rel": "update", - "http_header": { - "$ref": "../examples.json#/definitions/auth_header" - }, - "schema": { - "type": "object", - "additionalProperties": false, - "properties": { - "domain_names": { - "$ref": "#/definitions/domain_names" - }, - "certificate_id": { - "$ref": "#/definitions/certificate_id" - }, - "ssl_forced": { - "$ref": "#/definitions/ssl_forced" - }, - "hsts_enabled": { - "$ref": "#/definitions/hsts_enabled" - }, - "hsts_subdomains": { - "$ref": "#/definitions/hsts_enabled" - }, - "http2_support": { - "$ref": "#/definitions/http2_support" - }, - "advanced_config": { - "$ref": "#/definitions/advanced_config" - }, - "meta": { - "$ref": "#/definitions/meta" - } - } - }, - "targetSchema": { - "properties": { - "$ref": "#/properties" - } - } - }, - { - "title": "Delete", - "description": "Deletes a existing 404 Host", - "href": "/nginx/dead-hosts/{definitions.identity.example}", - "access": "private", - "method": "DELETE", - "rel": "delete", - "http_header": { - "$ref": "../examples.json#/definitions/auth_header" - }, - "targetSchema": { - "type": "boolean" - } - }, - { - "title": "Enable", - "description": "Enables a existing 404 Host", - "href": "/nginx/dead-hosts/{definitions.identity.example}/enable", - "access": "private", - "method": "POST", - "rel": "update", - "http_header": { - "$ref": "../examples.json#/definitions/auth_header" - }, - "targetSchema": { - "type": "boolean" - } - }, - { - "title": "Disable", - "description": "Disables a existing 404 Host", - "href": "/nginx/dead-hosts/{definitions.identity.example}/disable", - "access": "private", - "method": "POST", - "rel": "update", - "http_header": { - "$ref": "../examples.json#/definitions/auth_header" - }, - "targetSchema": { - "type": "boolean" - } - } - ] -} diff --git a/backend/schema/endpoints/proxy-hosts.json b/backend/schema/endpoints/proxy-hosts.json deleted file mode 100644 index 9a3fff2fc..000000000 --- a/backend/schema/endpoints/proxy-hosts.json +++ /dev/null @@ -1,387 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "endpoints/proxy-hosts", - "title": "Proxy Hosts", - "description": "Endpoints relating to Proxy Hosts", - "stability": "stable", - "type": "object", - "definitions": { - "id": { - "$ref": "../definitions.json#/definitions/id" - }, - "created_on": { - "$ref": "../definitions.json#/definitions/created_on" - }, - "modified_on": { - "$ref": "../definitions.json#/definitions/modified_on" - }, - "domain_names": { - "$ref": "../definitions.json#/definitions/domain_names" - }, - "forward_scheme": { - "type": "string", - "enum": ["http", "https"] - }, - "forward_host": { - "type": "string", - "minLength": 1, - "maxLength": 255 - }, - "forward_port": { - "type": "integer", - "minimum": 1, - "maximum": 65535 - }, - "certificate_id": { - "$ref": "../definitions.json#/definitions/certificate_id" - }, - "ssl_forced": { - "$ref": "../definitions.json#/definitions/ssl_forced" - }, - "hsts_enabled": { - "$ref": "../definitions.json#/definitions/hsts_enabled" - }, - "hsts_subdomains": { - "$ref": "../definitions.json#/definitions/hsts_subdomains" - }, - "http2_support": { - "$ref": "../definitions.json#/definitions/http2_support" - }, - "block_exploits": { - "$ref": "../definitions.json#/definitions/block_exploits" - }, - "caching_enabled": { - "$ref": "../definitions.json#/definitions/caching_enabled" - }, - "allow_websocket_upgrade": { - "description": "Allow Websocket Upgrade for all paths", - "example": true, - "type": "boolean" - }, - "access_list_id": { - "$ref": "../definitions.json#/definitions/access_list_id" - }, - "advanced_config": { - "type": "string" - }, - "enabled": { - "$ref": "../definitions.json#/definitions/enabled" - }, - "meta": { - "type": "object" - }, - "locations": { - "type": "array", - "minItems": 0, - "items": { - "type": "object", - "required": [ - "forward_scheme", - "forward_host", - "forward_port", - "path" - ], - "additionalProperties": false, - "properties": { - "id": { - "type": ["integer", "null"] - }, - "path": { - "type": "string", - "minLength": 1 - }, - "forward_scheme": { - "$ref": "#/definitions/forward_scheme" - }, - "forward_host": { - "$ref": "#/definitions/forward_host" - }, - "forward_port": { - "$ref": "#/definitions/forward_port" - }, - "forward_path": { - "type": "string" - }, - "advanced_config": { - "type": "string" - } - } - } - } - }, - "properties": { - "id": { - "$ref": "#/definitions/id" - }, - "created_on": { - "$ref": "#/definitions/created_on" - }, - "modified_on": { - "$ref": "#/definitions/modified_on" - }, - "domain_names": { - "$ref": "#/definitions/domain_names" - }, - "forward_scheme": { - "$ref": "#/definitions/forward_scheme" - }, - "forward_host": { - "$ref": "#/definitions/forward_host" - }, - "forward_port": { - "$ref": "#/definitions/forward_port" - }, - "certificate_id": { - "$ref": "#/definitions/certificate_id" - }, - "ssl_forced": { - "$ref": "#/definitions/ssl_forced" - }, - "hsts_enabled": { - "$ref": "#/definitions/hsts_enabled" - }, - "hsts_subdomains": { - "$ref": "#/definitions/hsts_subdomains" - }, - "http2_support": { - "$ref": "#/definitions/http2_support" - }, - "block_exploits": { - "$ref": "#/definitions/block_exploits" - }, - "caching_enabled": { - "$ref": "#/definitions/caching_enabled" - }, - "allow_websocket_upgrade": { - "$ref": "#/definitions/allow_websocket_upgrade" - }, - "access_list_id": { - "$ref": "#/definitions/access_list_id" - }, - "advanced_config": { - "$ref": "#/definitions/advanced_config" - }, - "enabled": { - "$ref": "#/definitions/enabled" - }, - "meta": { - "$ref": "#/definitions/meta" - }, - "locations": { - "$ref": "#/definitions/locations" - } - }, - "links": [ - { - "title": "List", - "description": "Returns a list of Proxy Hosts", - "href": "/nginx/proxy-hosts", - "access": "private", - "method": "GET", - "rel": "self", - "http_header": { - "$ref": "../examples.json#/definitions/auth_header" - }, - "targetSchema": { - "type": "array", - "items": { - "$ref": "#/properties" - } - } - }, - { - "title": "Create", - "description": "Creates a new Proxy Host", - "href": "/nginx/proxy-hosts", - "access": "private", - "method": "POST", - "rel": "create", - "http_header": { - "$ref": "../examples.json#/definitions/auth_header" - }, - "schema": { - "type": "object", - "additionalProperties": false, - "required": [ - "domain_names", - "forward_scheme", - "forward_host", - "forward_port" - ], - "properties": { - "domain_names": { - "$ref": "#/definitions/domain_names" - }, - "forward_scheme": { - "$ref": "#/definitions/forward_scheme" - }, - "forward_host": { - "$ref": "#/definitions/forward_host" - }, - "forward_port": { - "$ref": "#/definitions/forward_port" - }, - "certificate_id": { - "$ref": "#/definitions/certificate_id" - }, - "ssl_forced": { - "$ref": "#/definitions/ssl_forced" - }, - "hsts_enabled": { - "$ref": "#/definitions/hsts_enabled" - }, - "hsts_subdomains": { - "$ref": "#/definitions/hsts_enabled" - }, - "http2_support": { - "$ref": "#/definitions/http2_support" - }, - "block_exploits": { - "$ref": "#/definitions/block_exploits" - }, - "caching_enabled": { - "$ref": "#/definitions/caching_enabled" - }, - "allow_websocket_upgrade": { - "$ref": "#/definitions/allow_websocket_upgrade" - }, - "access_list_id": { - "$ref": "#/definitions/access_list_id" - }, - "advanced_config": { - "$ref": "#/definitions/advanced_config" - }, - "enabled": { - "$ref": "#/definitions/enabled" - }, - "meta": { - "$ref": "#/definitions/meta" - }, - "locations": { - "$ref": "#/definitions/locations" - } - } - }, - "targetSchema": { - "properties": { - "$ref": "#/properties" - } - } - }, - { - "title": "Update", - "description": "Updates a existing Proxy Host", - "href": "/nginx/proxy-hosts/{definitions.identity.example}", - "access": "private", - "method": "PUT", - "rel": "update", - "http_header": { - "$ref": "../examples.json#/definitions/auth_header" - }, - "schema": { - "type": "object", - "additionalProperties": false, - "properties": { - "domain_names": { - "$ref": "#/definitions/domain_names" - }, - "forward_scheme": { - "$ref": "#/definitions/forward_scheme" - }, - "forward_host": { - "$ref": "#/definitions/forward_host" - }, - "forward_port": { - "$ref": "#/definitions/forward_port" - }, - "certificate_id": { - "$ref": "#/definitions/certificate_id" - }, - "ssl_forced": { - "$ref": "#/definitions/ssl_forced" - }, - "hsts_enabled": { - "$ref": "#/definitions/hsts_enabled" - }, - "hsts_subdomains": { - "$ref": "#/definitions/hsts_enabled" - }, - "http2_support": { - "$ref": "#/definitions/http2_support" - }, - "block_exploits": { - "$ref": "#/definitions/block_exploits" - }, - "caching_enabled": { - "$ref": "#/definitions/caching_enabled" - }, - "allow_websocket_upgrade": { - "$ref": "#/definitions/allow_websocket_upgrade" - }, - "access_list_id": { - "$ref": "#/definitions/access_list_id" - }, - "advanced_config": { - "$ref": "#/definitions/advanced_config" - }, - "enabled": { - "$ref": "#/definitions/enabled" - }, - "meta": { - "$ref": "#/definitions/meta" - }, - "locations": { - "$ref": "#/definitions/locations" - } - } - }, - "targetSchema": { - "properties": { - "$ref": "#/properties" - } - } - }, - { - "title": "Delete", - "description": "Deletes a existing Proxy Host", - "href": "/nginx/proxy-hosts/{definitions.identity.example}", - "access": "private", - "method": "DELETE", - "rel": "delete", - "http_header": { - "$ref": "../examples.json#/definitions/auth_header" - }, - "targetSchema": { - "type": "boolean" - } - }, - { - "title": "Enable", - "description": "Enables a existing Proxy Host", - "href": "/nginx/proxy-hosts/{definitions.identity.example}/enable", - "access": "private", - "method": "POST", - "rel": "update", - "http_header": { - "$ref": "../examples.json#/definitions/auth_header" - }, - "targetSchema": { - "type": "boolean" - } - }, - { - "title": "Disable", - "description": "Disables a existing Proxy Host", - "href": "/nginx/proxy-hosts/{definitions.identity.example}/disable", - "access": "private", - "method": "POST", - "rel": "update", - "http_header": { - "$ref": "../examples.json#/definitions/auth_header" - }, - "targetSchema": { - "type": "boolean" - } - } - ] -} diff --git a/backend/schema/endpoints/redirection-hosts.json b/backend/schema/endpoints/redirection-hosts.json deleted file mode 100644 index 14a469985..000000000 --- a/backend/schema/endpoints/redirection-hosts.json +++ /dev/null @@ -1,305 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "endpoints/redirection-hosts", - "title": "Redirection Hosts", - "description": "Endpoints relating to Redirection Hosts", - "stability": "stable", - "type": "object", - "definitions": { - "id": { - "$ref": "../definitions.json#/definitions/id" - }, - "created_on": { - "$ref": "../definitions.json#/definitions/created_on" - }, - "modified_on": { - "$ref": "../definitions.json#/definitions/modified_on" - }, - "domain_names": { - "$ref": "../definitions.json#/definitions/domain_names" - }, - "forward_http_code": { - "$ref": "../definitions.json#/definitions/http_code" - }, - "forward_scheme": { - "$ref": "../definitions.json#/definitions/scheme" - }, - "forward_domain_name": { - "$ref": "../definitions.json#/definitions/domain_name" - }, - "preserve_path": { - "description": "Should the path be preserved", - "example": true, - "type": "boolean" - }, - "certificate_id": { - "$ref": "../definitions.json#/definitions/certificate_id" - }, - "ssl_forced": { - "$ref": "../definitions.json#/definitions/ssl_forced" - }, - "hsts_enabled": { - "$ref": "../definitions.json#/definitions/hsts_enabled" - }, - "hsts_subdomains": { - "$ref": "../definitions.json#/definitions/hsts_subdomains" - }, - "http2_support": { - "$ref": "../definitions.json#/definitions/http2_support" - }, - "block_exploits": { - "$ref": "../definitions.json#/definitions/block_exploits" - }, - "advanced_config": { - "type": "string" - }, - "enabled": { - "$ref": "../definitions.json#/definitions/enabled" - }, - "meta": { - "type": "object" - } - }, - "properties": { - "id": { - "$ref": "#/definitions/id" - }, - "created_on": { - "$ref": "#/definitions/created_on" - }, - "modified_on": { - "$ref": "#/definitions/modified_on" - }, - "domain_names": { - "$ref": "#/definitions/domain_names" - }, - "forward_http_code": { - "$ref": "#/definitions/forward_http_code" - }, - "forward_scheme": { - "$ref": "#/definitions/forward_scheme" - }, - "forward_domain_name": { - "$ref": "#/definitions/forward_domain_name" - }, - "preserve_path": { - "$ref": "#/definitions/preserve_path" - }, - "certificate_id": { - "$ref": "#/definitions/certificate_id" - }, - "ssl_forced": { - "$ref": "#/definitions/ssl_forced" - }, - "hsts_enabled": { - "$ref": "#/definitions/hsts_enabled" - }, - "hsts_subdomains": { - "$ref": "#/definitions/hsts_subdomains" - }, - "http2_support": { - "$ref": "#/definitions/http2_support" - }, - "block_exploits": { - "$ref": "#/definitions/block_exploits" - }, - "advanced_config": { - "$ref": "#/definitions/advanced_config" - }, - "enabled": { - "$ref": "#/definitions/enabled" - }, - "meta": { - "$ref": "#/definitions/meta" - } - }, - "links": [ - { - "title": "List", - "description": "Returns a list of Redirection Hosts", - "href": "/nginx/redirection-hosts", - "access": "private", - "method": "GET", - "rel": "self", - "http_header": { - "$ref": "../examples.json#/definitions/auth_header" - }, - "targetSchema": { - "type": "array", - "items": { - "$ref": "#/properties" - } - } - }, - { - "title": "Create", - "description": "Creates a new Redirection Host", - "href": "/nginx/redirection-hosts", - "access": "private", - "method": "POST", - "rel": "create", - "http_header": { - "$ref": "../examples.json#/definitions/auth_header" - }, - "schema": { - "type": "object", - "additionalProperties": false, - "required": [ - "domain_names", - "forward_scheme", - "forward_http_code", - "forward_domain_name" - ], - "properties": { - "domain_names": { - "$ref": "#/definitions/domain_names" - }, - "forward_http_code": { - "$ref": "#/definitions/forward_http_code" - }, - "forward_scheme": { - "$ref": "#/definitions/forward_scheme" - }, - "forward_domain_name": { - "$ref": "#/definitions/forward_domain_name" - }, - "preserve_path": { - "$ref": "#/definitions/preserve_path" - }, - "certificate_id": { - "$ref": "#/definitions/certificate_id" - }, - "ssl_forced": { - "$ref": "#/definitions/ssl_forced" - }, - "hsts_enabled": { - "$ref": "#/definitions/hsts_enabled" - }, - "hsts_subdomains": { - "$ref": "#/definitions/hsts_enabled" - }, - "http2_support": { - "$ref": "#/definitions/http2_support" - }, - "block_exploits": { - "$ref": "#/definitions/block_exploits" - }, - "advanced_config": { - "$ref": "#/definitions/advanced_config" - }, - "meta": { - "$ref": "#/definitions/meta" - } - } - }, - "targetSchema": { - "properties": { - "$ref": "#/properties" - } - } - }, - { - "title": "Update", - "description": "Updates a existing Redirection Host", - "href": "/nginx/redirection-hosts/{definitions.identity.example}", - "access": "private", - "method": "PUT", - "rel": "update", - "http_header": { - "$ref": "../examples.json#/definitions/auth_header" - }, - "schema": { - "type": "object", - "additionalProperties": false, - "properties": { - "domain_names": { - "$ref": "#/definitions/domain_names" - }, - "forward_http_code": { - "$ref": "#/definitions/forward_http_code" - }, - "forward_scheme": { - "$ref": "#/definitions/forward_scheme" - }, - "forward_domain_name": { - "$ref": "#/definitions/forward_domain_name" - }, - "preserve_path": { - "$ref": "#/definitions/preserve_path" - }, - "certificate_id": { - "$ref": "#/definitions/certificate_id" - }, - "ssl_forced": { - "$ref": "#/definitions/ssl_forced" - }, - "hsts_enabled": { - "$ref": "#/definitions/hsts_enabled" - }, - "hsts_subdomains": { - "$ref": "#/definitions/hsts_enabled" - }, - "http2_support": { - "$ref": "#/definitions/http2_support" - }, - "block_exploits": { - "$ref": "#/definitions/block_exploits" - }, - "advanced_config": { - "$ref": "#/definitions/advanced_config" - }, - "meta": { - "$ref": "#/definitions/meta" - } - } - }, - "targetSchema": { - "properties": { - "$ref": "#/properties" - } - } - }, - { - "title": "Delete", - "description": "Deletes a existing Redirection Host", - "href": "/nginx/redirection-hosts/{definitions.identity.example}", - "access": "private", - "method": "DELETE", - "rel": "delete", - "http_header": { - "$ref": "../examples.json#/definitions/auth_header" - }, - "targetSchema": { - "type": "boolean" - } - }, - { - "title": "Enable", - "description": "Enables a existing Redirection Host", - "href": "/nginx/redirection-hosts/{definitions.identity.example}/enable", - "access": "private", - "method": "POST", - "rel": "update", - "http_header": { - "$ref": "../examples.json#/definitions/auth_header" - }, - "targetSchema": { - "type": "boolean" - } - }, - { - "title": "Disable", - "description": "Disables a existing Redirection Host", - "href": "/nginx/redirection-hosts/{definitions.identity.example}/disable", - "access": "private", - "method": "POST", - "rel": "update", - "http_header": { - "$ref": "../examples.json#/definitions/auth_header" - }, - "targetSchema": { - "type": "boolean" - } - } - ] -} diff --git a/backend/schema/endpoints/settings.json b/backend/schema/endpoints/settings.json deleted file mode 100644 index 29e2865ae..000000000 --- a/backend/schema/endpoints/settings.json +++ /dev/null @@ -1,99 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "endpoints/settings", - "title": "Settings", - "description": "Endpoints relating to Settings", - "stability": "stable", - "type": "object", - "definitions": { - "id": { - "$ref": "../definitions.json#/definitions/setting_id" - }, - "name": { - "description": "Name", - "example": "Default Site", - "type": "string", - "minLength": 2, - "maxLength": 100 - }, - "description": { - "description": "Description", - "example": "Default Site", - "type": "string", - "minLength": 2, - "maxLength": 255 - }, - "value": { - "description": "Value", - "example": "404", - "type": "string", - "maxLength": 255 - }, - "meta": { - "type": "object" - } - }, - "links": [ - { - "title": "List", - "description": "Returns a list of Settings", - "href": "/settings", - "access": "private", - "method": "GET", - "rel": "self", - "http_header": { - "$ref": "../examples.json#/definitions/auth_header" - }, - "targetSchema": { - "type": "array", - "items": { - "$ref": "#/properties" - } - } - }, - { - "title": "Update", - "description": "Updates a existing Setting", - "href": "/settings/{definitions.identity.example}", - "access": "private", - "method": "PUT", - "rel": "update", - "http_header": { - "$ref": "../examples.json#/definitions/auth_header" - }, - "schema": { - "type": "object", - "properties": { - "value": { - "$ref": "#/definitions/value" - }, - "meta": { - "$ref": "#/definitions/meta" - } - } - }, - "targetSchema": { - "properties": { - "$ref": "#/properties" - } - } - } - ], - "properties": { - "id": { - "$ref": "#/definitions/id" - }, - "name": { - "$ref": "#/definitions/description" - }, - "description": { - "$ref": "#/definitions/description" - }, - "value": { - "$ref": "#/definitions/value" - }, - "meta": { - "$ref": "#/definitions/meta" - } - } -} diff --git a/backend/schema/endpoints/streams.json b/backend/schema/endpoints/streams.json deleted file mode 100644 index 159c8036e..000000000 --- a/backend/schema/endpoints/streams.json +++ /dev/null @@ -1,234 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "endpoints/streams", - "title": "Streams", - "description": "Endpoints relating to Streams", - "stability": "stable", - "type": "object", - "definitions": { - "id": { - "$ref": "../definitions.json#/definitions/id" - }, - "created_on": { - "$ref": "../definitions.json#/definitions/created_on" - }, - "modified_on": { - "$ref": "../definitions.json#/definitions/modified_on" - }, - "incoming_port": { - "type": "integer", - "minimum": 1, - "maximum": 65535 - }, - "forwarding_host": { - "anyOf": [ - { - "$ref": "../definitions.json#/definitions/domain_name" - }, - { - "type": "string", - "format": "ipv4" - }, - { - "type": "string", - "format": "ipv6" - } - ] - }, - "forwarding_port": { - "type": "integer", - "minimum": 1, - "maximum": 65535 - }, - "tcp_forwarding": { - "type": "boolean" - }, - "udp_forwarding": { - "type": "boolean" - }, - "enabled": { - "$ref": "../definitions.json#/definitions/enabled" - }, - "meta": { - "type": "object" - } - }, - "properties": { - "id": { - "$ref": "#/definitions/id" - }, - "created_on": { - "$ref": "#/definitions/created_on" - }, - "modified_on": { - "$ref": "#/definitions/modified_on" - }, - "incoming_port": { - "$ref": "#/definitions/incoming_port" - }, - "forwarding_host": { - "$ref": "#/definitions/forwarding_host" - }, - "forwarding_port": { - "$ref": "#/definitions/forwarding_port" - }, - "tcp_forwarding": { - "$ref": "#/definitions/tcp_forwarding" - }, - "udp_forwarding": { - "$ref": "#/definitions/udp_forwarding" - }, - "enabled": { - "$ref": "#/definitions/enabled" - }, - "meta": { - "$ref": "#/definitions/meta" - } - }, - "links": [ - { - "title": "List", - "description": "Returns a list of Steams", - "href": "/nginx/streams", - "access": "private", - "method": "GET", - "rel": "self", - "http_header": { - "$ref": "../examples.json#/definitions/auth_header" - }, - "targetSchema": { - "type": "array", - "items": { - "$ref": "#/properties" - } - } - }, - { - "title": "Create", - "description": "Creates a new Stream", - "href": "/nginx/streams", - "access": "private", - "method": "POST", - "rel": "create", - "http_header": { - "$ref": "../examples.json#/definitions/auth_header" - }, - "schema": { - "type": "object", - "additionalProperties": false, - "required": [ - "incoming_port", - "forwarding_host", - "forwarding_port" - ], - "properties": { - "incoming_port": { - "$ref": "#/definitions/incoming_port" - }, - "forwarding_host": { - "$ref": "#/definitions/forwarding_host" - }, - "forwarding_port": { - "$ref": "#/definitions/forwarding_port" - }, - "tcp_forwarding": { - "$ref": "#/definitions/tcp_forwarding" - }, - "udp_forwarding": { - "$ref": "#/definitions/udp_forwarding" - }, - "meta": { - "$ref": "#/definitions/meta" - } - } - }, - "targetSchema": { - "properties": { - "$ref": "#/properties" - } - } - }, - { - "title": "Update", - "description": "Updates a existing Stream", - "href": "/nginx/streams/{definitions.identity.example}", - "access": "private", - "method": "PUT", - "rel": "update", - "http_header": { - "$ref": "../examples.json#/definitions/auth_header" - }, - "schema": { - "type": "object", - "additionalProperties": false, - "properties": { - "incoming_port": { - "$ref": "#/definitions/incoming_port" - }, - "forwarding_host": { - "$ref": "#/definitions/forwarding_host" - }, - "forwarding_port": { - "$ref": "#/definitions/forwarding_port" - }, - "tcp_forwarding": { - "$ref": "#/definitions/tcp_forwarding" - }, - "udp_forwarding": { - "$ref": "#/definitions/udp_forwarding" - }, - "meta": { - "$ref": "#/definitions/meta" - } - } - }, - "targetSchema": { - "properties": { - "$ref": "#/properties" - } - } - }, - { - "title": "Delete", - "description": "Deletes a existing Stream", - "href": "/nginx/streams/{definitions.identity.example}", - "access": "private", - "method": "DELETE", - "rel": "delete", - "http_header": { - "$ref": "../examples.json#/definitions/auth_header" - }, - "targetSchema": { - "type": "boolean" - } - }, - { - "title": "Enable", - "description": "Enables a existing Stream", - "href": "/nginx/streams/{definitions.identity.example}/enable", - "access": "private", - "method": "POST", - "rel": "update", - "http_header": { - "$ref": "../examples.json#/definitions/auth_header" - }, - "targetSchema": { - "type": "boolean" - } - }, - { - "title": "Disable", - "description": "Disables a existing Stream", - "href": "/nginx/streams/{definitions.identity.example}/disable", - "access": "private", - "method": "POST", - "rel": "update", - "http_header": { - "$ref": "../examples.json#/definitions/auth_header" - }, - "targetSchema": { - "type": "boolean" - } - } - ] -} diff --git a/backend/schema/endpoints/tokens.json b/backend/schema/endpoints/tokens.json deleted file mode 100644 index 920af63f4..000000000 --- a/backend/schema/endpoints/tokens.json +++ /dev/null @@ -1,100 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "endpoints/tokens", - "title": "Token", - "description": "Tokens are required to authenticate against the API", - "stability": "stable", - "type": "object", - "definitions": { - "identity": { - "description": "Email Address or other 3rd party providers identifier", - "example": "john@example.com", - "type": "string" - }, - "secret": { - "description": "A password or key", - "example": "correct horse battery staple", - "type": "string" - }, - "token": { - "description": "JWT", - "example": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.O_frfYM8RzmRsUNigHtu0_jZ_utSejyr1axMGa8rlsk", - "type": "string" - }, - "expires": { - "description": "Token expiry time", - "format": "date-time", - "type": "string" - }, - "scope": { - "description": "Scope of the Token, defaults to 'user'", - "example": "user", - "type": "string" - } - }, - "links": [ - { - "title": "Create", - "description": "Creates a new token.", - "href": "/tokens", - "access": "public", - "method": "POST", - "rel": "create", - "schema": { - "type": "object", - "required": [ - "identity", - "secret" - ], - "properties": { - "identity": { - "$ref": "#/definitions/identity" - }, - "secret": { - "$ref": "#/definitions/secret" - }, - "scope": { - "$ref": "#/definitions/scope" - } - } - }, - "targetSchema": { - "type": "object", - "properties": { - "token": { - "$ref": "#/definitions/token" - }, - "expires": { - "$ref": "#/definitions/expires" - } - } - } - }, - { - "title": "Refresh", - "description": "Returns a new token.", - "href": "/tokens", - "access": "private", - "method": "GET", - "rel": "self", - "http_header": { - "$ref": "../examples.json#/definitions/auth_header" - }, - "schema": {}, - "targetSchema": { - "type": "object", - "properties": { - "token": { - "$ref": "#/definitions/token" - }, - "expires": { - "$ref": "#/definitions/expires" - }, - "scope": { - "$ref": "#/definitions/scope" - } - } - } - } - ] -} diff --git a/backend/schema/endpoints/users.json b/backend/schema/endpoints/users.json deleted file mode 100644 index 42f44eac7..000000000 --- a/backend/schema/endpoints/users.json +++ /dev/null @@ -1,287 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "endpoints/users", - "title": "Users", - "description": "Endpoints relating to Users", - "stability": "stable", - "type": "object", - "definitions": { - "id": { - "$ref": "../definitions.json#/definitions/id" - }, - "created_on": { - "$ref": "../definitions.json#/definitions/created_on" - }, - "modified_on": { - "$ref": "../definitions.json#/definitions/modified_on" - }, - "name": { - "description": "Name", - "example": "Jamie Curnow", - "type": "string", - "minLength": 2, - "maxLength": 100 - }, - "nickname": { - "description": "Nickname", - "example": "Jamie", - "type": "string", - "minLength": 2, - "maxLength": 50 - }, - "email": { - "$ref": "../definitions.json#/definitions/email" - }, - "avatar": { - "description": "Avatar", - "example": "http://somewhere.jpg", - "type": "string", - "minLength": 2, - "maxLength": 150, - "readOnly": true - }, - "roles": { - "description": "Roles", - "example": [ - "admin" - ], - "type": "array" - }, - "is_disabled": { - "description": "Is Disabled", - "example": false, - "type": "boolean" - } - }, - "links": [ - { - "title": "List", - "description": "Returns a list of Users", - "href": "/users", - "access": "private", - "method": "GET", - "rel": "self", - "http_header": { - "$ref": "../examples.json#/definitions/auth_header" - }, - "targetSchema": { - "type": "array", - "items": { - "$ref": "#/properties" - } - } - }, - { - "title": "Create", - "description": "Creates a new User", - "href": "/users", - "access": "private", - "method": "POST", - "rel": "create", - "http_header": { - "$ref": "../examples.json#/definitions/auth_header" - }, - "schema": { - "type": "object", - "required": [ - "name", - "nickname", - "email" - ], - "properties": { - "name": { - "$ref": "#/definitions/name" - }, - "nickname": { - "$ref": "#/definitions/nickname" - }, - "email": { - "$ref": "#/definitions/email" - }, - "roles": { - "$ref": "#/definitions/roles" - }, - "is_disabled": { - "$ref": "#/definitions/is_disabled" - }, - "auth": { - "type": "object", - "description": "Auth Credentials", - "example": { - "type": "password", - "secret": "bigredhorsebanana" - } - } - } - }, - "targetSchema": { - "properties": { - "$ref": "#/properties" - } - } - }, - { - "title": "Update", - "description": "Updates a existing User", - "href": "/users/{definitions.identity.example}", - "access": "private", - "method": "PUT", - "rel": "update", - "http_header": { - "$ref": "../examples.json#/definitions/auth_header" - }, - "schema": { - "type": "object", - "properties": { - "name": { - "$ref": "#/definitions/name" - }, - "nickname": { - "$ref": "#/definitions/nickname" - }, - "email": { - "$ref": "#/definitions/email" - }, - "roles": { - "$ref": "#/definitions/roles" - }, - "is_disabled": { - "$ref": "#/definitions/is_disabled" - } - } - }, - "targetSchema": { - "properties": { - "$ref": "#/properties" - } - } - }, - { - "title": "Delete", - "description": "Deletes a existing User", - "href": "/users/{definitions.identity.example}", - "access": "private", - "method": "DELETE", - "rel": "delete", - "http_header": { - "$ref": "../examples.json#/definitions/auth_header" - }, - "targetSchema": { - "type": "boolean" - } - }, - { - "title": "Set Password", - "description": "Sets a password for an existing User", - "href": "/users/{definitions.identity.example}/auth", - "access": "private", - "method": "PUT", - "rel": "update", - "http_header": { - "$ref": "../examples.json#/definitions/auth_header" - }, - "schema": { - "type": "object", - "required": [ - "type", - "secret" - ], - "properties": { - "type": { - "type": "string", - "pattern": "^password$" - }, - "current": { - "type": "string", - "minLength": 1, - "maxLength": 64 - }, - "secret": { - "type": "string", - "minLength": 8, - "maxLength": 64 - } - } - }, - "targetSchema": { - "type": "boolean" - } - }, - { - "title": "Set Permissions", - "description": "Sets Permissions for a User", - "href": "/users/{definitions.identity.example}/permissions", - "access": "private", - "method": "PUT", - "rel": "update", - "http_header": { - "$ref": "../examples.json#/definitions/auth_header" - }, - "schema": { - "type": "object", - "properties": { - "visibility": { - "type": "string", - "pattern": "^(all|user)$" - }, - "access_lists": { - "type": "string", - "pattern": "^(hidden|view|manage)$" - }, - "dead_hosts": { - "type": "string", - "pattern": "^(hidden|view|manage)$" - }, - "proxy_hosts": { - "type": "string", - "pattern": "^(hidden|view|manage)$" - }, - "redirection_hosts": { - "type": "string", - "pattern": "^(hidden|view|manage)$" - }, - "streams": { - "type": "string", - "pattern": "^(hidden|view|manage)$" - }, - "certificates": { - "type": "string", - "pattern": "^(hidden|view|manage)$" - } - } - }, - "targetSchema": { - "type": "boolean" - } - } - ], - "properties": { - "id": { - "$ref": "#/definitions/id" - }, - "created_on": { - "$ref": "#/definitions/created_on" - }, - "modified_on": { - "$ref": "#/definitions/modified_on" - }, - "name": { - "$ref": "#/definitions/name" - }, - "nickname": { - "$ref": "#/definitions/nickname" - }, - "email": { - "$ref": "#/definitions/email" - }, - "avatar": { - "$ref": "#/definitions/avatar" - }, - "roles": { - "$ref": "#/definitions/roles" - }, - "is_disabled": { - "$ref": "#/definitions/is_disabled" - } - } -} diff --git a/backend/schema/examples.json b/backend/schema/examples.json deleted file mode 100644 index 37bc6c4d3..000000000 --- a/backend/schema/examples.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "examples", - "type": "object", - "definitions": { - "name": { - "description": "Name", - "example": "John Smith", - "type": "string", - "minLength": 1, - "maxLength": 255 - }, - "auth_header": { - "Authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.O_frfYM8RzmRsUNigHtu0_jZ_utSejyr1axMGa8rlsk", - "X-API-Version": "next" - }, - "token": { - "type": "string", - "description": "JWT", - "example": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.O_frfYM8RzmRsUNigHtu0_jZ_utSejyr1axMGa8rlsk" - } - } -} diff --git a/backend/schema/index.js b/backend/schema/index.js new file mode 100644 index 000000000..87b75f257 --- /dev/null +++ b/backend/schema/index.js @@ -0,0 +1,41 @@ +const refParser = require('@apidevtools/json-schema-ref-parser'); + +let compiledSchema = null; + +module.exports = { + + /** + * Compiles the schema, by dereferencing it, only once + * and returns the memory cached value + */ + getCompiledSchema: async () => { + if (compiledSchema === null) { + compiledSchema = await refParser.dereference(__dirname + '/swagger.json', { + mutateInputSchema: false, + }); + } + return compiledSchema; + }, + + /** + * Scans the schema for the validation schema for the given path and method + * and returns it. + * + * @param {string} path + * @param {string} method + * @returns string|null + */ + getValidationSchema: (path, method) => { + if (compiledSchema !== null && + typeof compiledSchema.paths[path] !== 'undefined' && + typeof compiledSchema.paths[path][method] !== 'undefined' && + typeof compiledSchema.paths[path][method].requestBody !== 'undefined' && + typeof compiledSchema.paths[path][method].requestBody.content !== 'undefined' && + typeof compiledSchema.paths[path][method].requestBody.content['application/json'] !== 'undefined' && + typeof compiledSchema.paths[path][method].requestBody.content['application/json'].schema !== 'undefined' + ) { + return compiledSchema.paths[path][method].requestBody.content['application/json'].schema; + } + return null; + } +}; diff --git a/backend/schema/index.json b/backend/schema/index.json deleted file mode 100644 index 6e7d1c8af..000000000 --- a/backend/schema/index.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "root", - "title": "Nginx Proxy Manager REST API", - "description": "This is the Nginx Proxy Manager REST API", - "version": "2.0.0", - "links": [ - { - "href": "http://npm.example.com/api", - "rel": "self" - } - ], - "properties": { - "tokens": { - "$ref": "endpoints/tokens.json" - }, - "users": { - "$ref": "endpoints/users.json" - }, - "proxy-hosts": { - "$ref": "endpoints/proxy-hosts.json" - }, - "redirection-hosts": { - "$ref": "endpoints/redirection-hosts.json" - }, - "dead-hosts": { - "$ref": "endpoints/dead-hosts.json" - }, - "streams": { - "$ref": "endpoints/streams.json" - }, - "certificates": { - "$ref": "endpoints/certificates.json" - }, - "access-lists": { - "$ref": "endpoints/access-lists.json" - }, - "settings": { - "$ref": "endpoints/settings.json" - } - } -} diff --git a/backend/schema/paths/audit-log/get.json b/backend/schema/paths/audit-log/get.json new file mode 100644 index 000000000..bc43e29dd --- /dev/null +++ b/backend/schema/paths/audit-log/get.json @@ -0,0 +1,53 @@ +{ + "operationId": "getAuditLog", + "summary": "Get Audit Log", + "tags": ["Audit Log"], + "security": [ + { + "BearerAuth": ["audit-log"] + } + ], + "responses": { + "200": { + "description": "200 response", + "content": { + "application/json": { + "examples": { + "default": { + "value": [ + { + "id": 7, + "created_on": "2024-10-08T13:09:54.000Z", + "modified_on": "2024-10-08T13:09:54.000Z", + "user_id": 1, + "object_type": "user", + "object_id": 3, + "action": "updated", + "meta": { + "name": "John Doe", + "permissions": { + "user_id": 3, + "visibility": "all", + "access_lists": "manage", + "dead_hosts": "hidden", + "proxy_hosts": "manage", + "redirection_hosts": "view", + "streams": "hidden", + "certificates": "manage", + "id": 3, + "modified_on": "2024-10-08T13:09:54.000Z", + "created_on": "2024-10-08T13:09:51.000Z" + } + } + } + ] + } + }, + "schema": { + "$ref": "../../components/audit-log-object.json" + } + } + } + } + } +} diff --git a/backend/schema/paths/get.json b/backend/schema/paths/get.json new file mode 100644 index 000000000..8c3a4e025 --- /dev/null +++ b/backend/schema/paths/get.json @@ -0,0 +1,29 @@ +{ + "operationId": "health", + "summary": "Returns the API health status", + "tags": ["Public"], + "responses": { + "200": { + "description": "200 response", + "content": { + "application/json": { + "examples": { + "default": { + "value": { + "status": "OK", + "version": { + "major": 2, + "minor": 1, + "revision": 0 + } + } + } + }, + "schema": { + "$ref": "../components/health-object.json" + } + } + } + } + } +} diff --git a/backend/schema/paths/nginx/access-lists/get.json b/backend/schema/paths/nginx/access-lists/get.json new file mode 100644 index 000000000..7774b906a --- /dev/null +++ b/backend/schema/paths/nginx/access-lists/get.json @@ -0,0 +1,50 @@ +{ + "operationId": "getAccessLists", + "summary": "Get all access lists", + "tags": ["Access Lists"], + "security": [ + { + "BearerAuth": ["access_lists"] + } + ], + "parameters": [ + { + "in": "query", + "name": "expand", + "description": "Expansions", + "schema": { + "type": "string", + "enum": ["owner", "items", "clients", "proxy_hosts"] + } + } + ], + "responses": { + "200": { + "description": "200 response", + "content": { + "application/json": { + "examples": { + "default": { + "value": [ + { + "id": 1, + "created_on": "2024-10-08T22:15:40.000Z", + "modified_on": "2024-10-08T22:15:40.000Z", + "owner_user_id": 1, + "name": "test1234", + "meta": {}, + "satisfy_any": 1, + "pass_auth": 0, + "proxy_host_count": 0 + } + ] + } + }, + "schema": { + "$ref": "../../../components/access-list-object.json" + } + } + } + } + } +} diff --git a/backend/schema/paths/nginx/access-lists/listID/delete.json b/backend/schema/paths/nginx/access-lists/listID/delete.json new file mode 100644 index 000000000..073585c8b --- /dev/null +++ b/backend/schema/paths/nginx/access-lists/listID/delete.json @@ -0,0 +1,39 @@ +{ + "operationId": "deleteAccessList", + "summary": "Delete a Access List", + "tags": ["Access Lists"], + "security": [ + { + "BearerAuth": ["access_lists"] + } + ], + "parameters": [ + { + "in": "path", + "name": "listID", + "schema": { + "type": "integer", + "minimum": 1 + }, + "required": true, + "example": 2 + } + ], + "responses": { + "200": { + "description": "200 response", + "content": { + "application/json": { + "examples": { + "default": { + "value": true + } + }, + "schema": { + "type": "boolean" + } + } + } + } + } +} diff --git a/backend/schema/paths/nginx/access-lists/listID/get.json b/backend/schema/paths/nginx/access-lists/listID/get.json new file mode 100644 index 000000000..011ad77e6 --- /dev/null +++ b/backend/schema/paths/nginx/access-lists/listID/get.json @@ -0,0 +1,49 @@ +{ + "operationId": "getAccessList", + "summary": "Get a access List", + "tags": ["Access Lists"], + "security": [ + { + "BearerAuth": ["access_lists"] + } + ], + "parameters": [ + { + "in": "path", + "name": "listID", + "schema": { + "type": "integer", + "minimum": 1 + }, + "required": true, + "example": 1 + } + ], + "responses": { + "200": { + "description": "200 response", + "content": { + "application/json": { + "examples": { + "default": { + "value": { + "id": 1, + "created_on": "2020-01-30T09:36:08.000Z", + "modified_on": "2020-01-30T09:41:04.000Z", + "is_disabled": 0, + "email": "jc@jc21.com", + "name": "Jamie Curnow", + "nickname": "James", + "avatar": "//www.gravatar.com/avatar/6193176330f8d38747f038c170ddb193?default=mm", + "roles": ["admin"] + } + } + }, + "schema": { + "$ref": "../../../../components/access-list-object.json" + } + } + } + } + } +} diff --git a/backend/schema/paths/nginx/access-lists/listID/put.json b/backend/schema/paths/nginx/access-lists/listID/put.json new file mode 100644 index 000000000..95ecaa619 --- /dev/null +++ b/backend/schema/paths/nginx/access-lists/listID/put.json @@ -0,0 +1,164 @@ +{ + "operationId": "updateAccessList", + "summary": "Update a Access List", + "tags": ["Access Lists"], + "security": [ + { + "BearerAuth": ["access_lists"] + } + ], + "parameters": [ + { + "in": "path", + "name": "listID", + "schema": { + "type": "integer", + "minimum": 1 + }, + "required": true, + "example": 2 + } + ], + "requestBody": { + "description": "Access List Payload", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "minProperties": 1, + "properties": { + "name": { + "$ref": "../../../../components/access-list-object.json#/properties/name" + }, + "satisfy_any": { + "$ref": "../../../../components/access-list-object.json#/properties/satisfy_any" + }, + "pass_auth": { + "$ref": "../../../../components/access-list-object.json#/properties/pass_auth" + }, + "items": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "properties": { + "username": { + "type": "string", + "minLength": 1 + }, + "password": { + "type": "string", + "minLength": 1 + } + } + } + }, + "clients": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "properties": { + "address": { + "oneOf": [ + { + "type": "string", + "pattern": "^([0-9]{1,3}\\.){3}[0-9]{1,3}(/([0-9]|[1-2][0-9]|3[0-2]))?$" + }, + { + "type": "string", + "pattern": "^s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:)))(%.+)?s*(/([0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8]))?$" + }, + { + "type": "string", + "pattern": "^all$" + } + ] + }, + "directive": { + "$ref": "../../../../components/access-list-object.json#/properties/directive" + } + } + } + } + } + } + } + } + }, + "responses": { + "200": { + "description": "200 response", + "content": { + "application/json": { + "examples": { + "default": { + "value": { + "id": 1, + "created_on": "2024-10-08T22:15:40.000Z", + "modified_on": "2024-10-08T22:34:34.000Z", + "owner_user_id": 1, + "name": "test123!!", + "meta": {}, + "satisfy_any": 1, + "pass_auth": 0, + "proxy_host_count": 0, + "owner": { + "id": 1, + "created_on": "2024-10-07T22:43:55.000Z", + "modified_on": "2024-10-08T12:52:54.000Z", + "is_deleted": 0, + "is_disabled": 0, + "email": "admin@example.com", + "name": "Administrator", + "nickname": "some guy", + "avatar": "//www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?default=mm", + "roles": ["admin"] + }, + "items": [ + { + "id": 1, + "created_on": "2024-10-08T22:15:40.000Z", + "modified_on": "2024-10-08T22:15:40.000Z", + "access_list_id": 1, + "username": "admin", + "password": "", + "meta": {}, + "hint": "a****" + }, + { + "id": 2, + "created_on": "2024-10-08T22:15:40.000Z", + "modified_on": "2024-10-08T22:15:40.000Z", + "access_list_id": 1, + "username": "asdad", + "password": "", + "meta": {}, + "hint": "a*****" + } + ], + "clients": [ + { + "id": 1, + "created_on": "2024-10-08T22:15:40.000Z", + "modified_on": "2024-10-08T22:15:40.000Z", + "access_list_id": 1, + "address": "127.0.0.1", + "directive": "allow", + "meta": {} + } + ], + "proxy_hosts": [] + } + } + }, + "schema": { + "$ref": "../../../../components/access-list-object.json" + } + } + } + } + } +} diff --git a/backend/schema/paths/nginx/access-lists/post.json b/backend/schema/paths/nginx/access-lists/post.json new file mode 100644 index 000000000..cb3af8f42 --- /dev/null +++ b/backend/schema/paths/nginx/access-lists/post.json @@ -0,0 +1,155 @@ +{ + "operationId": "createAccessList", + "summary": "Create a Access List", + "tags": ["Access Lists"], + "security": [ + { + "BearerAuth": ["access_lists"] + } + ], + "requestBody": { + "description": "Access List Payload", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "required": ["name"], + "properties": { + "name": { + "$ref": "../../../components/access-list-object.json#/properties/name" + }, + "satisfy_any": { + "$ref": "../../../components/access-list-object.json#/properties/satisfy_any" + }, + "pass_auth": { + "$ref": "../../../components/access-list-object.json#/properties/pass_auth" + }, + "items": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "properties": { + "username": { + "type": "string", + "minLength": 1 + }, + "password": { + "type": "string", + "minLength": 1 + } + } + } + }, + "clients": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "properties": { + "address": { + "oneOf": [ + { + "type": "string", + "pattern": "^([0-9]{1,3}\\.){3}[0-9]{1,3}(/([0-9]|[1-2][0-9]|3[0-2]))?$" + }, + { + "type": "string", + "pattern": "^s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:)))(%.+)?s*(/([0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8]))?$" + }, + { + "type": "string", + "pattern": "^all$" + } + ] + }, + "directive": { + "$ref": "../../../components/access-list-object.json#/properties/directive" + } + } + } + }, + "meta": { + "$ref": "../../../components/access-list-object.json#/properties/meta" + } + } + } + } + } + }, + "responses": { + "201": { + "description": "201 response", + "content": { + "application/json": { + "examples": { + "default": { + "value": { + "id": 1, + "created_on": "2024-10-08T22:15:40.000Z", + "modified_on": "2024-10-08T22:15:40.000Z", + "owner_user_id": 1, + "name": "test1234", + "meta": {}, + "satisfy_any": 1, + "pass_auth": 0, + "proxy_host_count": 0, + "owner": { + "id": 1, + "created_on": "2024-10-07T22:43:55.000Z", + "modified_on": "2024-10-08T12:52:54.000Z", + "is_deleted": 0, + "is_disabled": 0, + "email": "admin@example.com", + "name": "Administrator", + "nickname": "some guy", + "avatar": "//www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?default=mm", + "roles": ["admin"] + }, + "items": [ + { + "id": 1, + "created_on": "2024-10-08T22:15:40.000Z", + "modified_on": "2024-10-08T22:15:40.000Z", + "access_list_id": 1, + "username": "admin", + "password": "", + "meta": {}, + "hint": "a****" + }, + { + "id": 2, + "created_on": "2024-10-08T22:15:40.000Z", + "modified_on": "2024-10-08T22:15:40.000Z", + "access_list_id": 1, + "username": "asdad", + "password": "", + "meta": {}, + "hint": "a*****" + } + ], + "proxy_hosts": [], + "clients": [ + { + "id": 1, + "created_on": "2024-10-08T22:15:40.000Z", + "modified_on": "2024-10-08T22:15:40.000Z", + "access_list_id": 1, + "address": "127.0.0.1", + "directive": "allow", + "meta": {} + } + ] + } + } + }, + "schema": { + "$ref": "../../../components/access-list-object.json" + } + } + } + } + } +} diff --git a/backend/schema/paths/nginx/certificates/certID/delete.json b/backend/schema/paths/nginx/certificates/certID/delete.json new file mode 100644 index 000000000..0d40bcb8c --- /dev/null +++ b/backend/schema/paths/nginx/certificates/certID/delete.json @@ -0,0 +1,39 @@ +{ + "operationId": "deleteCertificate", + "summary": "Delete a Certificate", + "tags": ["Certificates"], + "security": [ + { + "BearerAuth": ["certificates"] + } + ], + "parameters": [ + { + "in": "path", + "name": "certID", + "schema": { + "type": "integer", + "minimum": 1 + }, + "required": true, + "example": 2 + } + ], + "responses": { + "200": { + "description": "200 response", + "content": { + "application/json": { + "examples": { + "default": { + "value": true + } + }, + "schema": { + "type": "boolean" + } + } + } + } + } +} diff --git a/backend/schema/paths/nginx/certificates/certID/download/get.json b/backend/schema/paths/nginx/certificates/certID/download/get.json new file mode 100644 index 000000000..4b858cae7 --- /dev/null +++ b/backend/schema/paths/nginx/certificates/certID/download/get.json @@ -0,0 +1,35 @@ +{ + "operationId": "downloadCertificate", + "summary": "Downloads a Certificate", + "tags": ["Certificates"], + "security": [ + { + "BearerAuth": ["certificates"] + } + ], + "parameters": [ + { + "in": "path", + "name": "certID", + "schema": { + "type": "integer", + "minimum": 1 + }, + "required": true, + "example": 1 + } + ], + "responses": { + "200": { + "description": "200 response", + "content": { + "application/zip": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + } + } +} diff --git a/backend/schema/paths/nginx/certificates/certID/get.json b/backend/schema/paths/nginx/certificates/certID/get.json new file mode 100644 index 000000000..22317b337 --- /dev/null +++ b/backend/schema/paths/nginx/certificates/certID/get.json @@ -0,0 +1,53 @@ +{ + "operationId": "getCertificate", + "summary": "Get a Certificate", + "tags": ["Certificates"], + "security": [ + { + "BearerAuth": ["certificates"] + } + ], + "parameters": [ + { + "in": "path", + "name": "certID", + "schema": { + "type": "integer", + "minimum": 1 + }, + "required": true, + "example": 1 + } + ], + "responses": { + "200": { + "description": "200 response", + "content": { + "application/json": { + "examples": { + "default": { + "value": { + "id": 4, + "created_on": "2024-10-09T05:31:58.000Z", + "modified_on": "2024-10-09T05:32:11.000Z", + "owner_user_id": 1, + "provider": "letsencrypt", + "nice_name": "test.example.com", + "domain_names": ["test.example.com"], + "expires_on": "2025-01-07T04:34:18.000Z", + "meta": { + "letsencrypt_email": "jc@jc21.com", + "letsencrypt_agree": true, + "dns_challenge": false + } + } + } + }, + "schema": { + "$ref": "../../../../components/certificate-object.json" + } + } + } + } + } +} diff --git a/backend/schema/paths/nginx/certificates/certID/renew/post.json b/backend/schema/paths/nginx/certificates/certID/renew/post.json new file mode 100644 index 000000000..7b32af04a --- /dev/null +++ b/backend/schema/paths/nginx/certificates/certID/renew/post.json @@ -0,0 +1,54 @@ +{ + "operationId": "renewCertificate", + "summary": "Renews a Certificate", + "tags": ["Certificates"], + "security": [ + { + "BearerAuth": ["certificates"] + } + ], + "parameters": [ + { + "in": "path", + "name": "certID", + "schema": { + "type": "integer", + "minimum": 1 + }, + "required": true, + "example": 1 + } + ], + "responses": { + "200": { + "description": "200 response", + "content": { + "application/json": { + "examples": { + "default": { + "value": { + "expires_on": "2025-01-07T06:41:58.000Z", + "modified_on": "2024-10-09T07:39:51.000Z", + "id": 4, + "created_on": "2024-10-09T05:31:58.000Z", + "owner_user_id": 1, + "is_deleted": 0, + "provider": "letsencrypt", + "nice_name": "My Test Cert", + "domain_names": ["test.jc21.supernerd.pro"], + "meta": { + "letsencrypt_email": "jc@jc21.com", + "letsencrypt_agree": true, + "dns_challenge": false + } + } + } + }, + "schema": { + "$ref": "../../../../../components/certificate-object.json" + } + } + } + } + } +} diff --git a/backend/schema/paths/nginx/certificates/certID/upload/post.json b/backend/schema/paths/nginx/certificates/certID/upload/post.json new file mode 100644 index 000000000..e9274856a --- /dev/null +++ b/backend/schema/paths/nginx/certificates/certID/upload/post.json @@ -0,0 +1,63 @@ +{ + "operationId": "uploadCertificate", + "summary": "Uploads a custom Certificate", + "tags": ["Certificates"], + "security": [ + { + "BearerAuth": ["certificates"] + } + ], + "parameters": [ + { + "in": "path", + "name": "certID", + "schema": { + "type": "integer", + "minimum": 1 + }, + "required": true, + "example": 1 + } + ], + "requestBody": { + "description": "Certificate Files", + "required": true, + "content": { + "multipart/form-data": { + "schema": { + "type": "object", + "additionalProperties": false, + "required": ["certificate", "certificate_key"], + "properties": { + "certificate": { + "type": "string" + }, + "certificate_key": { + "type": "string" + }, + "intermediate_certificate": { + "type": "string" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "200 response", + "content": { + "application/json": { + "examples": { + "default": { + "value": { + "certificate": "-----BEGIN CERTIFICATE-----\nMIIEYDCCAsigAwIBAgIRAPoSC0hvitb26ODMlsH6YbowDQYJKoZIhvcNAQELBQAw\ngZExHjAcBgNVBAoTFW1rY2VydCBkZXZlbG9wbWVudCBDQTEzMDEGA1UECwwqamN1\ncm5vd0BKYW1pZXMtTGFwdG9wLmxvY2FsIChKYW1pZSBDdXJub3cpMTowOAYDVQQD\nDDFta2NlcnQgamN1cm5vd0BKYW1pZXMtTGFwdG9wLmxvY2FsIChKYW1pZSBDdXJu\nb3cpMB4XDTI0MTAwOTA3MjIxN1oXDTI3MDEwOTA3MjIxN1owXjEnMCUGA1UEChMe\nbWtjZXJ0IGRldmVsb3BtZW50IGNlcnRpZmljYXRlMTMwMQYDVQQLDCpqY3Vybm93\nQEphbWllcy1MYXB0b3AubG9jYWwgKEphbWllIEN1cm5vdykwggEiMA0GCSqGSIb3\nDQEBAQUAA4IBDwAwggEKAoIBAQC1n9j9C5Bes1ndqACDckERauxXVNKCnUlUM1bu\nGBx1xc+j2e2Ar23wUJJuWBY18VfT8yqfqVDktO2wrbmvZvLuPmXePOKbIKS+XXh+\n2NG9L5bDG9rwGFCRXnbQj+GWCdMfzx14+CR1IHgeYz6Cv/Si2/LJPCh/CoBfM4hU\nQJON3lxAWrWBpdbZnKYMrxuPBRfW9OuzTbCVXToQoxRAHiOR9081Xn1WeoKr7kVB\nIa5UphlvWXa12w1YmUwJu7YndnJGIavLWeNCVc7ZEo+nS8Wr/4QWicatIWZXpVaE\nOPhRoeplQDxNWg5b/Q26rYoVd7PrCmRs7sVcH79XzGONeH1PAgMBAAGjZTBjMA4G\nA1UdDwEB/wQEAwIFoDATBgNVHSUEDDAKBggrBgEFBQcDATAfBgNVHSMEGDAWgBSB\n/vfmBUd4W7CvyEMl7YpMVQs8vTAbBgNVHREEFDASghB0ZXN0LmV4YW1wbGUuY29t\nMA0GCSqGSIb3DQEBCwUAA4IBgQASwON/jPAHzcARSenY0ZGY1m5OVTYoQ/JWH0oy\nl8SyFCQFEXt7UHDD/eTtLT0vMyc190nP57P8lTnZGf7hSinZz1B1d6V4cmzxpk0s\nVXZT+irL6bJVJoMBHRpllKAhGULIo33baTrWFKA0oBuWx4AevSWKcLW5j87kEawn\nATCuMQ1I3ifR1mSlB7X8fb+vF+571q0NGuB3a42j6rdtXJ6SmH4+9B4qO0sfHDNt\nIImpLCH/tycDpcYrGSCn1QrekFG1bSEh+Bb9i8rqMDSDsYrTFPZTuOQ3EtjGni9u\nm+rEP3OyJg+md8c+0LVP7/UU4QWWnw3/Wolo5kSCxE8vNTFqi4GhVbdLnUtcIdTV\nXxuR6cKyW87Snj1a0nG76ZLclt/akxDhtzqeV60BO0p8pmiev8frp+E94wFNYCmp\n1cr3CnMEGRaficLSDFC6EBENzlZW2BQT6OMIV+g0NBgSyQe39s2zcdEl5+SzDVuw\nhp8bJUp/QN7pnOVCDbjTQ+HVMXw=\n-----END CERTIFICATE-----\n", + "certificate_key": "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC1n9j9C5Bes1nd\nqACDckERauxXVNKCnUlUM1buGBx1xc+j2e2Ar23wUJJuWBY18VfT8yqfqVDktO2w\nrbmvZvLuPmXePOKbIKS+XXh+2NG9L5bDG9rwGFCRXnbQj+GWCdMfzx14+CR1IHge\nYz6Cv/Si2/LJPCh/CoBfM4hUQJON3lxAWrWBpdbZnKYMrxuPBRfW9OuzTbCVXToQ\noxRAHiOR9081Xn1WeoKr7kVBIa5UphlvWXa12w1YmUwJu7YndnJGIavLWeNCVc7Z\nEo+nS8Wr/4QWicatIWZXpVaEOPhRoeplQDxNWg5b/Q26rYoVd7PrCmRs7sVcH79X\nzGONeH1PAgMBAAECggEAANb3Wtwl07pCjRrMvc7WbC0xYIn82yu8/g2qtjkYUJcU\nia5lQbYN7RGCS85Oc/tkq48xQEG5JQWNH8b918jDEMTrFab0aUEyYcru1q9L8PL6\nYHaNgZSrMrDcHcS8h0QOXNRJT5jeGkiHJaTR0irvB526tqF3knbK9yW22KTfycUe\na0Z9voKn5xRk1DCbHi/nk2EpT7xnjeQeLFaTIRXbS68omkr4YGhwWm5OizoyEGZu\nW0Zum5BkQyMr6kor3wdxOTG97ske2rcyvvHi+ErnwL0xBv0qY0Dhe8DpuXpDezqw\no72yY8h31Fu84i7sAj24YuE5Df8DozItFXQpkgbQ6QKBgQDPrufhvIFm2S/MzBdW\nH8JxY7CJlJPyxOvc1NIl9RczQGAQR90kx52cgIcuIGEG6/wJ/xnGfMmW40F0DnQ+\nN+oLgB9SFxeLkRb7s9Z/8N3uIN8JJFYcerEOiRQeN2BXEEWJ7bUThNtsVrAcKoUh\nELsDmnHW/3V+GKwhd0vpk842+wKBgQDf4PGLG9PTE5tlAoyHFodJRd2RhTJQkwsU\nMDNjLJ+KecLv+Nl+QiJhoflG1ccqtSFlBSCG067CDQ5LV0xm3mLJ7pfJoMgjcq31\nqjEmX4Ls91GuVOPtbwst3yFKjsHaSoKB5fBvWRcKFpBUezM7Qcw2JP3+dQT+bQIq\ncMTkRWDSvQKBgQDOdCQFDjxg/lR7NQOZ1PaZe61aBz5P3pxNqa7ClvMaOsuEQ7w9\nvMYcdtRq8TsjA2JImbSI0TIg8gb2FQxPcYwTJKl+FICOeIwtaSg5hTtJZpnxX5LO\nutTaC0DZjNkTk5RdOdWA8tihyUdGqKoxJY2TVmwGe2rUEDjFB++J4inkEwKBgB6V\ng0nmtkxanFrzOzFlMXwgEEHF+Xaqb9QFNa/xs6XeNnREAapO7JV75Cr6H2hFMFe1\nmJjyqCgYUoCWX3iaHtLJRnEkBtNY4kzyQB6m46LtsnnnXO/dwKA2oDyoPfFNRoDq\nYatEd3JIXNU9s2T/+x7WdOBjKhh72dTkbPFmTPDdAoGAU6rlPBevqOFdObYxdPq8\nEQWu44xqky3Mf5sBpOwtu6rqCYuziLiN7K4sjN5GD5mb1cEU+oS92ZiNcUQ7MFXk\n8yTYZ7U0VcXyAcpYreWwE8thmb0BohJBr+Mp3wLTx32x0HKdO6vpUa0d35LUTUmM\nRrKmPK/msHKK/sVHiL+NFqo=\n-----END PRIVATE KEY-----\n" + } + } + } + } + } + } + } +} diff --git a/backend/schema/paths/nginx/certificates/get.json b/backend/schema/paths/nginx/certificates/get.json new file mode 100644 index 000000000..2f4b556af --- /dev/null +++ b/backend/schema/paths/nginx/certificates/get.json @@ -0,0 +1,54 @@ +{ + "operationId": "getCertificates", + "summary": "Get all certificates", + "tags": ["Certificates"], + "security": [ + { + "BearerAuth": ["certificates"] + } + ], + "parameters": [ + { + "in": "query", + "name": "expand", + "description": "Expansions", + "schema": { + "type": "string", + "enum": ["owner"] + } + } + ], + "responses": { + "200": { + "description": "200 response", + "content": { + "application/json": { + "examples": { + "default": { + "value": [ + { + "id": 4, + "created_on": "2024-10-09T05:31:58.000Z", + "modified_on": "2024-10-09T05:32:11.000Z", + "owner_user_id": 1, + "provider": "letsencrypt", + "nice_name": "test.example.com", + "domain_names": ["test.example.com"], + "expires_on": "2025-01-07T04:34:18.000Z", + "meta": { + "letsencrypt_email": "jc@jc21.com", + "letsencrypt_agree": true, + "dns_challenge": false + } + } + ] + } + }, + "schema": { + "$ref": "../../../components/certificate-list.json" + } + } + } + } + } +} diff --git a/backend/schema/paths/nginx/certificates/post.json b/backend/schema/paths/nginx/certificates/post.json new file mode 100644 index 000000000..cc4d91d6d --- /dev/null +++ b/backend/schema/paths/nginx/certificates/post.json @@ -0,0 +1,77 @@ +{ + "operationId": "createCertificate", + "summary": "Create a Certificate", + "tags": ["Certificates"], + "security": [ + { + "BearerAuth": ["certificates"] + } + ], + "requestBody": { + "description": "Certificate Payload", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "required": ["provider"], + "properties": { + "provider": { + "$ref": "../../../components/certificate-object.json#/properties/provider" + }, + "nice_name": { + "$ref": "../../../components/certificate-object.json#/properties/nice_name" + }, + "domain_names": { + "$ref": "../../../components/certificate-object.json#/properties/domain_names" + }, + "meta": { + "$ref": "../../../components/certificate-object.json#/properties/meta" + } + } + } + } + } + }, + "responses": { + "201": { + "description": "201 response", + "content": { + "application/json": { + "examples": { + "default": { + "value": { + "expires_on": "2025-01-07 04:30:17", + "modified_on": "2024-10-09 05:28:51", + "id": 5, + "created_on": "2024-10-09 05:28:35", + "owner_user_id": 1, + "is_deleted": 0, + "provider": "letsencrypt", + "nice_name": "test.example.com", + "domain_names": ["test.example.com"], + "meta": { + "letsencrypt_email": "jc@jc21.com", + "letsencrypt_agree": true, + "dns_challenge": false, + "letsencrypt_certificate": { + "cn": "test.example.com", + "issuer": "C = US, O = Let's Encrypt, CN = E5", + "dates": { + "from": 1728448218, + "to": 1736224217 + } + } + } + } + } + }, + "schema": { + "$ref": "../../../components/certificate-object.json" + } + } + } + } + } +} diff --git a/backend/schema/paths/nginx/certificates/test-http/get.json b/backend/schema/paths/nginx/certificates/test-http/get.json new file mode 100644 index 000000000..2b9a8dd3b --- /dev/null +++ b/backend/schema/paths/nginx/certificates/test-http/get.json @@ -0,0 +1,40 @@ +{ + "operationId": "testHttpReach", + "summary": "Test HTTP Reachability", + "tags": ["Certificates"], + "security": [ + { + "BearerAuth": ["certificates"] + } + ], + "parameters": [ + { + "in": "query", + "name": "domains", + "description": "Expansions", + "required": true, + "schema": { + "type": "string", + "example": "[\"test.example.ord\",\"test.example.com\",\"nonexistent.example.com\"]" + } + } + ], + "responses": { + "200": { + "description": "200 response", + "content": { + "application/json": { + "examples": { + "default": { + "value": { + "test.example.org": "ok", + "test.example.com": "other:Invalid domain or IP", + "nonexistent.example.com": "404" + } + } + } + } + } + } + } +} diff --git a/backend/schema/paths/nginx/certificates/validate/post.json b/backend/schema/paths/nginx/certificates/validate/post.json new file mode 100644 index 000000000..94f02f593 --- /dev/null +++ b/backend/schema/paths/nginx/certificates/validate/post.json @@ -0,0 +1,75 @@ +{ + "operationId": "validateCertificates", + "summary": "Validates given Custom Certificates", + "tags": ["Certificates"], + "security": [ + { + "BearerAuth": ["certificates"] + } + ], + "requestBody": { + "description": "Certificate Files", + "required": true, + "content": { + "multipart/form-data": { + "schema": { + "type": "object", + "additionalProperties": false, + "required": ["certificate", "certificate_key"], + "properties": { + "certificate": { + "type": "string" + }, + "certificate_key": { + "type": "string" + }, + "intermediate_certificate": { + "type": "string" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "200 response", + "content": { + "application/json": { + "examples": { + "default": { + "value": { + "certificate": { + "cn": "mkcert", + "issuer": "O = mkcert development CA, OU = jc@jc-Laptop.local (John Doe), CN = mkcert jc@jc-Laptop.local (John Doe)", + "dates": { + "from": 1728458537, + "to": 1799479337 + } + }, + "certificate_key": true + } + } + } + } + } + }, + "400": { + "description": "400 response", + "content": { + "application/json": { + "examples": { + "default": { + "value": { + "error": { + "code": 400, + "message": "Certificate is not valid" + } + } + } + } + } + } + } + } +} diff --git a/backend/schema/paths/nginx/dead-hosts/get.json b/backend/schema/paths/nginx/dead-hosts/get.json new file mode 100644 index 000000000..61e2b2784 --- /dev/null +++ b/backend/schema/paths/nginx/dead-hosts/get.json @@ -0,0 +1,57 @@ +{ + "operationId": "getDeadHosts", + "summary": "Get all 404 hosts", + "tags": ["404 Hosts"], + "security": [ + { + "BearerAuth": ["dead_hosts"] + } + ], + "parameters": [ + { + "in": "query", + "name": "expand", + "description": "Expansions", + "schema": { + "type": "string", + "enum": ["owner", "certificate"] + } + } + ], + "responses": { + "200": { + "description": "200 response", + "content": { + "application/json": { + "examples": { + "default": { + "value": [ + { + "id": 1, + "created_on": "2024-10-09T01:38:52.000Z", + "modified_on": "2024-10-09T01:38:52.000Z", + "owner_user_id": 1, + "domain_names": ["test.example.com"], + "certificate_id": 0, + "ssl_forced": 0, + "advanced_config": "", + "meta": { + "nginx_online": true, + "nginx_err": null + }, + "http2_support": 0, + "enabled": 1, + "hsts_enabled": 0, + "hsts_subdomains": 0 + } + ] + } + }, + "schema": { + "$ref": "../../../components/dead-host-list.json" + } + } + } + } + } +} diff --git a/backend/schema/paths/nginx/dead-hosts/hostID/delete.json b/backend/schema/paths/nginx/dead-hosts/hostID/delete.json new file mode 100644 index 000000000..f3aa81a5b --- /dev/null +++ b/backend/schema/paths/nginx/dead-hosts/hostID/delete.json @@ -0,0 +1,39 @@ +{ + "operationId": "deleteDeadHost", + "summary": "Delete a 404 Host", + "tags": ["404 Hosts"], + "security": [ + { + "BearerAuth": ["dead_hosts"] + } + ], + "parameters": [ + { + "in": "path", + "name": "hostID", + "schema": { + "type": "integer", + "minimum": 1 + }, + "required": true, + "example": 2 + } + ], + "responses": { + "200": { + "description": "200 response", + "content": { + "application/json": { + "examples": { + "default": { + "value": true + } + }, + "schema": { + "type": "boolean" + } + } + } + } + } +} diff --git a/backend/schema/paths/nginx/dead-hosts/hostID/disable/post.json b/backend/schema/paths/nginx/dead-hosts/hostID/disable/post.json new file mode 100644 index 000000000..528d05d35 --- /dev/null +++ b/backend/schema/paths/nginx/dead-hosts/hostID/disable/post.json @@ -0,0 +1,59 @@ +{ + "operationId": "disableDeadHost", + "summary": "Disable a 404 Host", + "tags": ["404 Hosts"], + "security": [ + { + "BearerAuth": ["dead_hosts"] + } + ], + "parameters": [ + { + "in": "path", + "name": "hostID", + "schema": { + "type": "integer", + "minimum": 1 + }, + "required": true, + "example": 2 + } + ], + "responses": { + "200": { + "description": "200 response", + "content": { + "application/json": { + "examples": { + "default": { + "value": true + } + }, + "schema": { + "type": "boolean" + } + } + } + }, + "400": { + "description": "400 response", + "content": { + "application/json": { + "examples": { + "default": { + "value": { + "error": { + "code": 400, + "message": "Host is already disabled" + } + } + } + }, + "schema": { + "$ref": "../../../../../components/error-object.json" + } + } + } + } + } +} diff --git a/backend/schema/paths/nginx/dead-hosts/hostID/enable/post.json b/backend/schema/paths/nginx/dead-hosts/hostID/enable/post.json new file mode 100644 index 000000000..dd95943a5 --- /dev/null +++ b/backend/schema/paths/nginx/dead-hosts/hostID/enable/post.json @@ -0,0 +1,59 @@ +{ + "operationId": "enableDeadHost", + "summary": "Enable a 404 Host", + "tags": ["404 Hosts"], + "security": [ + { + "BearerAuth": ["dead_hosts"] + } + ], + "parameters": [ + { + "in": "path", + "name": "hostID", + "schema": { + "type": "integer", + "minimum": 1 + }, + "required": true, + "example": 2 + } + ], + "responses": { + "200": { + "description": "200 response", + "content": { + "application/json": { + "examples": { + "default": { + "value": true + } + }, + "schema": { + "type": "boolean" + } + } + } + }, + "400": { + "description": "400 response", + "content": { + "application/json": { + "examples": { + "default": { + "value": { + "error": { + "code": 400, + "message": "Host is already enabled" + } + } + } + }, + "schema": { + "$ref": "../../../../../components/error-object.json" + } + } + } + } + } +} diff --git a/backend/schema/paths/nginx/dead-hosts/hostID/get.json b/backend/schema/paths/nginx/dead-hosts/hostID/get.json new file mode 100644 index 000000000..ae077c104 --- /dev/null +++ b/backend/schema/paths/nginx/dead-hosts/hostID/get.json @@ -0,0 +1,56 @@ +{ + "operationId": "getDeadHost", + "summary": "Get a 404 Host", + "tags": ["404 Hosts"], + "security": [ + { + "BearerAuth": ["dead_hosts"] + } + ], + "parameters": [ + { + "in": "path", + "name": "hostID", + "schema": { + "type": "integer", + "minimum": 1 + }, + "required": true, + "example": 1 + } + ], + "responses": { + "200": { + "description": "200 response", + "content": { + "application/json": { + "examples": { + "default": { + "value": { + "id": 1, + "created_on": "2024-10-09T01:38:52.000Z", + "modified_on": "2024-10-09T01:38:52.000Z", + "owner_user_id": 1, + "domain_names": ["test.example.com"], + "certificate_id": 0, + "ssl_forced": 0, + "advanced_config": "", + "meta": { + "nginx_online": true, + "nginx_err": null + }, + "http2_support": 0, + "enabled": 1, + "hsts_enabled": 0, + "hsts_subdomains": 0 + } + } + }, + "schema": { + "$ref": "../../../../components/dead-host-object.json" + } + } + } + } + } +} diff --git a/backend/schema/paths/nginx/dead-hosts/hostID/put.json b/backend/schema/paths/nginx/dead-hosts/hostID/put.json new file mode 100644 index 000000000..058aff172 --- /dev/null +++ b/backend/schema/paths/nginx/dead-hosts/hostID/put.json @@ -0,0 +1,110 @@ +{ + "operationId": "updateDeadHost", + "summary": "Update a 404 Host", + "tags": ["404 Hosts"], + "security": [ + { + "BearerAuth": ["dead_hosts"] + } + ], + "parameters": [ + { + "in": "path", + "name": "hostID", + "schema": { + "type": "integer", + "minimum": 1 + }, + "required": true, + "example": 2 + } + ], + "requestBody": { + "description": "404 Host Payload", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "minProperties": 1, + "properties": { + "domain_names": { + "$ref": "../../../../components/dead-host-object.json#/properties/domain_names" + }, + "certificate_id": { + "$ref": "../../../../components/dead-host-object.json#/properties/certificate_id" + }, + "ssl_forced": { + "$ref": "../../../../components/dead-host-object.json#/properties/ssl_forced" + }, + "hsts_enabled": { + "$ref": "../../../../components/dead-host-object.json#/properties/hsts_enabled" + }, + "hsts_subdomains": { + "$ref": "../../../../components/dead-host-object.json#/properties/hsts_subdomains" + }, + "http2_support": { + "$ref": "../../../../components/dead-host-object.json#/properties/http2_support" + }, + "advanced_config": { + "$ref": "../../../../components/dead-host-object.json#/properties/advanced_config" + }, + "meta": { + "$ref": "../../../../components/dead-host-object.json#/properties/meta" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "200 response", + "content": { + "application/json": { + "examples": { + "default": { + "value": { + "id": 1, + "created_on": "2024-10-09T01:38:52.000Z", + "modified_on": "2024-10-09T01:46:06.000Z", + "owner_user_id": 1, + "domain_names": ["test.example.com"], + "certificate_id": 0, + "ssl_forced": 0, + "advanced_config": "", + "meta": { + "nginx_online": true, + "nginx_err": null + }, + "http2_support": 0, + "enabled": 1, + "hsts_enabled": 0, + "hsts_subdomains": 0, + "owner": { + "id": 1, + "created_on": "2024-10-09T00:59:56.000Z", + "modified_on": "2024-10-09T00:59:56.000Z", + "is_deleted": 0, + "is_disabled": 0, + "email": "admin@example.com", + "name": "Administrator", + "nickname": "Admin", + "avatar": "", + "roles": ["admin"] + }, + "certificate": null, + "use_default_location": true, + "ipv6": true + } + } + }, + "schema": { + "$ref": "../../../../components/dead-host-object.json" + } + } + } + } + } +} diff --git a/backend/schema/paths/nginx/dead-hosts/post.json b/backend/schema/paths/nginx/dead-hosts/post.json new file mode 100644 index 000000000..b26174361 --- /dev/null +++ b/backend/schema/paths/nginx/dead-hosts/post.json @@ -0,0 +1,95 @@ +{ + "operationId": "create404Host", + "summary": "Create a 404 Host", + "tags": ["404 Hosts"], + "security": [ + { + "BearerAuth": ["dead_hosts"] + } + ], + "requestBody": { + "description": "404 Host Payload", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "required": ["domain_names"], + "properties": { + "domain_names": { + "$ref": "../../../components/dead-host-object.json#/properties/domain_names" + }, + "certificate_id": { + "$ref": "../../../components/dead-host-object.json#/properties/certificate_id" + }, + "ssl_forced": { + "$ref": "../../../components/dead-host-object.json#/properties/ssl_forced" + }, + "hsts_enabled": { + "$ref": "../../../components/dead-host-object.json#/properties/hsts_enabled" + }, + "hsts_subdomains": { + "$ref": "../../../components/dead-host-object.json#/properties/hsts_subdomains" + }, + "http2_support": { + "$ref": "../../../components/dead-host-object.json#/properties/http2_support" + }, + "advanced_config": { + "$ref": "../../../components/dead-host-object.json#/properties/advanced_config" + }, + "meta": { + "$ref": "../../../components/dead-host-object.json#/properties/meta" + } + } + } + } + } + }, + "responses": { + "201": { + "description": "201 response", + "content": { + "application/json": { + "examples": { + "default": { + "value": { + "id": 1, + "created_on": "2024-10-09T01:38:52.000Z", + "modified_on": "2024-10-09T01:38:52.000Z", + "owner_user_id": 1, + "domain_names": ["test.example.com"], + "certificate_id": 0, + "ssl_forced": 0, + "advanced_config": "", + "meta": {}, + "http2_support": 0, + "enabled": 1, + "hsts_enabled": 0, + "hsts_subdomains": 0, + "certificate": null, + "owner": { + "id": 1, + "created_on": "2024-10-09T00:59:56.000Z", + "modified_on": "2024-10-09T00:59:56.000Z", + "is_deleted": 0, + "is_disabled": 0, + "email": "admin@example.com", + "name": "Administrator", + "nickname": "Admin", + "avatar": "", + "roles": ["admin"] + }, + "use_default_location": true, + "ipv6": true + } + } + }, + "schema": { + "$ref": "../../../components/dead-host-object.json" + } + } + } + } + } +} diff --git a/backend/schema/paths/nginx/proxy-hosts/get.json b/backend/schema/paths/nginx/proxy-hosts/get.json new file mode 100644 index 000000000..9e9a7855b --- /dev/null +++ b/backend/schema/paths/nginx/proxy-hosts/get.json @@ -0,0 +1,65 @@ +{ + "operationId": "getProxyHosts", + "summary": "Get all proxy hosts", + "tags": ["Proxy Hosts"], + "security": [ + { + "BearerAuth": ["proxy_hosts"] + } + ], + "parameters": [ + { + "in": "query", + "name": "expand", + "description": "Expansions", + "schema": { + "type": "string", + "enum": ["access_list", "owner", "certificate"] + } + } + ], + "responses": { + "200": { + "description": "200 response", + "content": { + "application/json": { + "examples": { + "default": { + "value": [ + { + "id": 1, + "created_on": "2024-10-08T23:23:03.000Z", + "modified_on": "2024-10-08T23:23:04.000Z", + "owner_user_id": 1, + "domain_names": ["test.example.com"], + "forward_host": "127.0.0.1", + "forward_port": 8989, + "access_list_id": 0, + "certificate_id": 0, + "ssl_forced": 0, + "caching_enabled": 0, + "block_exploits": 0, + "advanced_config": "", + "meta": { + "nginx_online": true, + "nginx_err": null + }, + "allow_websocket_upgrade": 0, + "http2_support": 0, + "forward_scheme": "http", + "enabled": 1, + "locations": null, + "hsts_enabled": 0, + "hsts_subdomains": 0 + } + ] + } + }, + "schema": { + "$ref": "../../../components/proxy-host-list.json" + } + } + } + } + } +} diff --git a/backend/schema/paths/nginx/proxy-hosts/hostID/delete.json b/backend/schema/paths/nginx/proxy-hosts/hostID/delete.json new file mode 100644 index 000000000..991ef0e9e --- /dev/null +++ b/backend/schema/paths/nginx/proxy-hosts/hostID/delete.json @@ -0,0 +1,39 @@ +{ + "operationId": "deleteProxyHost", + "summary": "Delete a Proxy Host", + "tags": ["Proxy Hosts"], + "security": [ + { + "BearerAuth": ["proxy_hosts"] + } + ], + "parameters": [ + { + "in": "path", + "name": "hostID", + "schema": { + "type": "integer", + "minimum": 1 + }, + "required": true, + "example": 2 + } + ], + "responses": { + "200": { + "description": "200 response", + "content": { + "application/json": { + "examples": { + "default": { + "value": true + } + }, + "schema": { + "type": "boolean" + } + } + } + } + } +} diff --git a/backend/schema/paths/nginx/proxy-hosts/hostID/disable/post.json b/backend/schema/paths/nginx/proxy-hosts/hostID/disable/post.json new file mode 100644 index 000000000..1ff95e8f9 --- /dev/null +++ b/backend/schema/paths/nginx/proxy-hosts/hostID/disable/post.json @@ -0,0 +1,59 @@ +{ + "operationId": "disableProxyHost", + "summary": "Disable a Proxy Host", + "tags": ["Proxy Hosts"], + "security": [ + { + "BearerAuth": ["proxy_hosts"] + } + ], + "parameters": [ + { + "in": "path", + "name": "hostID", + "schema": { + "type": "integer", + "minimum": 1 + }, + "required": true, + "example": 2 + } + ], + "responses": { + "200": { + "description": "200 response", + "content": { + "application/json": { + "examples": { + "default": { + "value": true + } + }, + "schema": { + "type": "boolean" + } + } + } + }, + "400": { + "description": "400 response", + "content": { + "application/json": { + "examples": { + "default": { + "value": { + "error": { + "code": 400, + "message": "Host is already disabled" + } + } + } + }, + "schema": { + "$ref": "../../../../../components/error-object.json" + } + } + } + } + } +} diff --git a/backend/schema/paths/nginx/proxy-hosts/hostID/enable/post.json b/backend/schema/paths/nginx/proxy-hosts/hostID/enable/post.json new file mode 100644 index 000000000..3a5694b9c --- /dev/null +++ b/backend/schema/paths/nginx/proxy-hosts/hostID/enable/post.json @@ -0,0 +1,59 @@ +{ + "operationId": "enableProxyHost", + "summary": "Enable a Proxy Host", + "tags": ["Proxy Hosts"], + "security": [ + { + "BearerAuth": ["proxy_hosts"] + } + ], + "parameters": [ + { + "in": "path", + "name": "hostID", + "schema": { + "type": "integer", + "minimum": 1 + }, + "required": true, + "example": 2 + } + ], + "responses": { + "200": { + "description": "200 response", + "content": { + "application/json": { + "examples": { + "default": { + "value": true + } + }, + "schema": { + "type": "boolean" + } + } + } + }, + "400": { + "description": "400 response", + "content": { + "application/json": { + "examples": { + "default": { + "value": { + "error": { + "code": 400, + "message": "Host is already enabled" + } + } + } + }, + "schema": { + "$ref": "../../../../../components/error-object.json" + } + } + } + } + } +} diff --git a/backend/schema/paths/nginx/proxy-hosts/hostID/get.json b/backend/schema/paths/nginx/proxy-hosts/hostID/get.json new file mode 100644 index 000000000..250bf0326 --- /dev/null +++ b/backend/schema/paths/nginx/proxy-hosts/hostID/get.json @@ -0,0 +1,64 @@ +{ + "operationId": "getProxyHost", + "summary": "Get a Proxy Host", + "tags": ["Proxy Hosts"], + "security": [ + { + "BearerAuth": ["proxy_hosts"] + } + ], + "parameters": [ + { + "in": "path", + "name": "hostID", + "schema": { + "type": "integer", + "minimum": 1 + }, + "required": true, + "example": 1 + } + ], + "responses": { + "200": { + "description": "200 response", + "content": { + "application/json": { + "examples": { + "default": { + "value": { + "id": 1, + "created_on": "2024-10-08T23:23:03.000Z", + "modified_on": "2024-10-08T23:26:38.000Z", + "owner_user_id": 1, + "domain_names": ["test.example.com"], + "forward_host": "192.168.0.10", + "forward_port": 8989, + "access_list_id": 0, + "certificate_id": 0, + "ssl_forced": 0, + "caching_enabled": 0, + "block_exploits": 0, + "advanced_config": "", + "meta": { + "nginx_online": true, + "nginx_err": null + }, + "allow_websocket_upgrade": 0, + "http2_support": 0, + "forward_scheme": "http", + "enabled": 1, + "locations": null, + "hsts_enabled": 0, + "hsts_subdomains": 0 + } + } + }, + "schema": { + "$ref": "../../../../components/proxy-host-object.json" + } + } + } + } + } +} diff --git a/backend/schema/paths/nginx/proxy-hosts/hostID/put.json b/backend/schema/paths/nginx/proxy-hosts/hostID/put.json new file mode 100644 index 000000000..9028c6ac5 --- /dev/null +++ b/backend/schema/paths/nginx/proxy-hosts/hostID/put.json @@ -0,0 +1,145 @@ +{ + "operationId": "updateProxyHost", + "summary": "Update a Proxy Host", + "tags": ["Proxy Hosts"], + "security": [ + { + "BearerAuth": ["proxy_hosts"] + } + ], + "parameters": [ + { + "in": "path", + "name": "hostID", + "schema": { + "type": "integer", + "minimum": 1 + }, + "required": true, + "example": 2 + } + ], + "requestBody": { + "description": "Proxy Host Payload", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "minProperties": 1, + "properties": { + "domain_names": { + "$ref": "../../../../components/proxy-host-object.json#/properties/domain_names" + }, + "forward_scheme": { + "$ref": "../../../../components/proxy-host-object.json#/properties/forward_scheme" + }, + "forward_host": { + "$ref": "../../../../components/proxy-host-object.json#/properties/forward_host" + }, + "forward_port": { + "$ref": "../../../../components/proxy-host-object.json#/properties/forward_port" + }, + "certificate_id": { + "$ref": "../../../../components/proxy-host-object.json#/properties/certificate_id" + }, + "ssl_forced": { + "$ref": "../../../../components/proxy-host-object.json#/properties/ssl_forced" + }, + "hsts_enabled": { + "$ref": "../../../../components/proxy-host-object.json#/properties/hsts_enabled" + }, + "hsts_subdomains": { + "$ref": "../../../../components/proxy-host-object.json#/properties/hsts_subdomains" + }, + "http2_support": { + "$ref": "../../../../components/proxy-host-object.json#/properties/http2_support" + }, + "block_exploits": { + "$ref": "../../../../components/proxy-host-object.json#/properties/block_exploits" + }, + "caching_enabled": { + "$ref": "../../../../components/proxy-host-object.json#/properties/caching_enabled" + }, + "allow_websocket_upgrade": { + "$ref": "../../../../components/proxy-host-object.json#/properties/allow_websocket_upgrade" + }, + "access_list_id": { + "$ref": "../../../../components/proxy-host-object.json#/properties/access_list_id" + }, + "advanced_config": { + "$ref": "../../../../components/proxy-host-object.json#/properties/advanced_config" + }, + "enabled": { + "$ref": "../../../../components/proxy-host-object.json#/properties/enabled" + }, + "meta": { + "$ref": "../../../../components/proxy-host-object.json#/properties/meta" + }, + "locations": { + "$ref": "../../../../components/proxy-host-object.json#/properties/locations" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "200 response", + "content": { + "application/json": { + "examples": { + "default": { + "value": { + "id": 1, + "created_on": "2024-10-08T23:23:03.000Z", + "modified_on": "2024-10-08T23:26:37.000Z", + "owner_user_id": 1, + "domain_names": ["test.example.com"], + "forward_host": "192.168.0.10", + "forward_port": 8989, + "access_list_id": 0, + "certificate_id": 0, + "ssl_forced": 0, + "caching_enabled": 0, + "block_exploits": 0, + "advanced_config": "", + "meta": { + "nginx_online": true, + "nginx_err": null + }, + "allow_websocket_upgrade": 0, + "http2_support": 0, + "forward_scheme": "http", + "enabled": 1, + "hsts_enabled": 0, + "hsts_subdomains": 0, + "owner": { + "id": 1, + "created_on": "2024-10-07T22:43:55.000Z", + "modified_on": "2024-10-08T12:52:54.000Z", + "is_deleted": 0, + "is_disabled": 0, + "email": "admin@example.com", + "name": "Administrator", + "nickname": "some guy", + "avatar": "//www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?default=mm", + "roles": ["admin"] + }, + "certificate": null, + "access_list": null, + "use_default_location": true, + "ipv6": true + } + } + }, + "schema": { + "$ref": "../../../../components/proxy-host-object.json" + } + } + } + } + } +} diff --git a/backend/schema/paths/nginx/proxy-hosts/post.json b/backend/schema/paths/nginx/proxy-hosts/post.json new file mode 100644 index 000000000..5f61ff4c0 --- /dev/null +++ b/backend/schema/paths/nginx/proxy-hosts/post.json @@ -0,0 +1,130 @@ +{ + "operationId": "createProxyHost", + "summary": "Create a Proxy Host", + "tags": ["Proxy Hosts"], + "security": [ + { + "BearerAuth": ["proxy_hosts"] + } + ], + "requestBody": { + "description": "Proxy Host Payload", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "required": ["domain_names", "forward_scheme", "forward_host", "forward_port"], + "properties": { + "domain_names": { + "$ref": "../../../components/proxy-host-object.json#/properties/domain_names" + }, + "forward_scheme": { + "$ref": "../../../components/proxy-host-object.json#/properties/forward_scheme" + }, + "forward_host": { + "$ref": "../../../components/proxy-host-object.json#/properties/forward_host" + }, + "forward_port": { + "$ref": "../../../components/proxy-host-object.json#/properties/forward_port" + }, + "certificate_id": { + "$ref": "../../../components/proxy-host-object.json#/properties/certificate_id" + }, + "ssl_forced": { + "$ref": "../../../components/proxy-host-object.json#/properties/ssl_forced" + }, + "hsts_enabled": { + "$ref": "../../../components/proxy-host-object.json#/properties/hsts_enabled" + }, + "hsts_subdomains": { + "$ref": "../../../components/proxy-host-object.json#/properties/hsts_subdomains" + }, + "http2_support": { + "$ref": "../../../components/proxy-host-object.json#/properties/http2_support" + }, + "block_exploits": { + "$ref": "../../../components/proxy-host-object.json#/properties/block_exploits" + }, + "caching_enabled": { + "$ref": "../../../components/proxy-host-object.json#/properties/caching_enabled" + }, + "allow_websocket_upgrade": { + "$ref": "../../../components/proxy-host-object.json#/properties/allow_websocket_upgrade" + }, + "access_list_id": { + "$ref": "../../../components/proxy-host-object.json#/properties/access_list_id" + }, + "advanced_config": { + "$ref": "../../../components/proxy-host-object.json#/properties/advanced_config" + }, + "enabled": { + "$ref": "../../../components/proxy-host-object.json#/properties/enabled" + }, + "meta": { + "$ref": "../../../components/proxy-host-object.json#/properties/meta" + }, + "locations": { + "$ref": "../../../components/proxy-host-object.json#/properties/locations" + } + } + } + } + } + }, + "responses": { + "201": { + "description": "201 response", + "content": { + "application/json": { + "examples": { + "default": { + "value": { + "id": 1, + "created_on": "2024-10-08T23:23:03.000Z", + "modified_on": "2024-10-08T23:23:03.000Z", + "owner_user_id": 1, + "domain_names": ["test.example.com"], + "forward_host": "127.0.0.1", + "forward_port": 8989, + "access_list_id": 0, + "certificate_id": 0, + "ssl_forced": 0, + "caching_enabled": 0, + "block_exploits": 0, + "advanced_config": "", + "meta": {}, + "allow_websocket_upgrade": 0, + "http2_support": 0, + "forward_scheme": "http", + "enabled": 1, + "hsts_enabled": 0, + "hsts_subdomains": 0, + "certificate": null, + "owner": { + "id": 1, + "created_on": "2024-10-07T22:43:55.000Z", + "modified_on": "2024-10-08T12:52:54.000Z", + "is_deleted": 0, + "is_disabled": 0, + "email": "admin@example.com", + "name": "Administrator", + "nickname": "some guy", + "avatar": "//www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?default=mm", + "roles": ["admin"] + }, + "access_list": null, + "use_default_location": true, + "ipv6": true + } + } + }, + "schema": { + "$ref": "../../../components/proxy-host-object.json" + } + } + } + } + } +} diff --git a/backend/schema/paths/nginx/redirection-hosts/get.json b/backend/schema/paths/nginx/redirection-hosts/get.json new file mode 100644 index 000000000..24adbc78d --- /dev/null +++ b/backend/schema/paths/nginx/redirection-hosts/get.json @@ -0,0 +1,62 @@ +{ + "operationId": "getRedirectionHosts", + "summary": "Get all Redirection hosts", + "tags": ["Redirection Hosts"], + "security": [ + { + "BearerAuth": ["redirection_hosts"] + } + ], + "parameters": [ + { + "in": "query", + "name": "expand", + "description": "Expansions", + "schema": { + "type": "string", + "enum": ["owner", "certificate"] + } + } + ], + "responses": { + "200": { + "description": "200 response", + "content": { + "application/json": { + "examples": { + "default": { + "value": [ + { + "id": 1, + "created_on": "2024-10-09T01:13:12.000Z", + "modified_on": "2024-10-09T01:13:13.000Z", + "owner_user_id": 1, + "domain_names": ["test.example.com"], + "forward_domain_name": "something-else.com", + "preserve_path": 0, + "certificate_id": 0, + "ssl_forced": 0, + "block_exploits": 0, + "advanced_config": "", + "meta": { + "nginx_online": true, + "nginx_err": null + }, + "http2_support": 0, + "enabled": 1, + "hsts_enabled": 0, + "hsts_subdomains": 0, + "forward_scheme": "http", + "forward_http_code": 301 + } + ] + } + }, + "schema": { + "$ref": "../../../components/redirection-host-list.json" + } + } + } + } + } +} diff --git a/backend/schema/paths/nginx/redirection-hosts/hostID/delete.json b/backend/schema/paths/nginx/redirection-hosts/hostID/delete.json new file mode 100644 index 000000000..7330f3623 --- /dev/null +++ b/backend/schema/paths/nginx/redirection-hosts/hostID/delete.json @@ -0,0 +1,39 @@ +{ + "operationId": "deleteRedirectionHost", + "summary": "Delete a Redirection Host", + "tags": ["Redirection Hosts"], + "security": [ + { + "BearerAuth": ["redirection_hosts"] + } + ], + "parameters": [ + { + "in": "path", + "name": "hostID", + "schema": { + "type": "integer", + "minimum": 1 + }, + "required": true, + "example": 2 + } + ], + "responses": { + "200": { + "description": "200 response", + "content": { + "application/json": { + "examples": { + "default": { + "value": true + } + }, + "schema": { + "type": "boolean" + } + } + } + } + } +} diff --git a/backend/schema/paths/nginx/redirection-hosts/hostID/disable/post.json b/backend/schema/paths/nginx/redirection-hosts/hostID/disable/post.json new file mode 100644 index 000000000..7531ac36b --- /dev/null +++ b/backend/schema/paths/nginx/redirection-hosts/hostID/disable/post.json @@ -0,0 +1,59 @@ +{ + "operationId": "disableRedirectionHost", + "summary": "Disable a Redirection Host", + "tags": ["Redirection Hosts"], + "security": [ + { + "BearerAuth": ["redirection_hosts"] + } + ], + "parameters": [ + { + "in": "path", + "name": "hostID", + "schema": { + "type": "integer", + "minimum": 1 + }, + "required": true, + "example": 2 + } + ], + "responses": { + "200": { + "description": "200 response", + "content": { + "application/json": { + "examples": { + "default": { + "value": true + } + }, + "schema": { + "type": "boolean" + } + } + } + }, + "400": { + "description": "400 response", + "content": { + "application/json": { + "examples": { + "default": { + "value": { + "error": { + "code": 400, + "message": "Host is already disabled" + } + } + } + }, + "schema": { + "$ref": "../../../../../components/error-object.json" + } + } + } + } + } +} diff --git a/backend/schema/paths/nginx/redirection-hosts/hostID/enable/post.json b/backend/schema/paths/nginx/redirection-hosts/hostID/enable/post.json new file mode 100644 index 000000000..60f4fafd6 --- /dev/null +++ b/backend/schema/paths/nginx/redirection-hosts/hostID/enable/post.json @@ -0,0 +1,59 @@ +{ + "operationId": "enableRedirectionHost", + "summary": "Enable a Redirection Host", + "tags": ["Redirection Hosts"], + "security": [ + { + "BearerAuth": ["redirection_hosts"] + } + ], + "parameters": [ + { + "in": "path", + "name": "hostID", + "schema": { + "type": "integer", + "minimum": 1 + }, + "required": true, + "example": 2 + } + ], + "responses": { + "200": { + "description": "200 response", + "content": { + "application/json": { + "examples": { + "default": { + "value": true + } + }, + "schema": { + "type": "boolean" + } + } + } + }, + "400": { + "description": "400 response", + "content": { + "application/json": { + "examples": { + "default": { + "value": { + "error": { + "code": 400, + "message": "Host is already enabled" + } + } + } + }, + "schema": { + "$ref": "../../../../../components/error-object.json" + } + } + } + } + } +} diff --git a/backend/schema/paths/nginx/redirection-hosts/hostID/get.json b/backend/schema/paths/nginx/redirection-hosts/hostID/get.json new file mode 100644 index 000000000..f20ff296c --- /dev/null +++ b/backend/schema/paths/nginx/redirection-hosts/hostID/get.json @@ -0,0 +1,61 @@ +{ + "operationId": "getRedirectionHost", + "summary": "Get a Redirection Host", + "tags": ["Redirection Hosts"], + "security": [ + { + "BearerAuth": ["redirection_hosts"] + } + ], + "parameters": [ + { + "in": "path", + "name": "hostID", + "schema": { + "type": "integer", + "minimum": 1 + }, + "required": true, + "example": 1 + } + ], + "responses": { + "200": { + "description": "200 response", + "content": { + "application/json": { + "examples": { + "default": { + "value": { + "id": 1, + "created_on": "2024-10-09T01:13:12.000Z", + "modified_on": "2024-10-09T01:13:13.000Z", + "owner_user_id": 1, + "domain_names": ["test.example.com"], + "forward_domain_name": "something-else.com", + "preserve_path": 0, + "certificate_id": 0, + "ssl_forced": 0, + "block_exploits": 0, + "advanced_config": "", + "meta": { + "nginx_online": true, + "nginx_err": null + }, + "http2_support": 0, + "enabled": 1, + "hsts_enabled": 0, + "hsts_subdomains": 0, + "forward_scheme": "http", + "forward_http_code": 301 + } + } + }, + "schema": { + "$ref": "../../../../components/redirection-host-object.json" + } + } + } + } + } +} diff --git a/backend/schema/paths/nginx/redirection-hosts/hostID/put.json b/backend/schema/paths/nginx/redirection-hosts/hostID/put.json new file mode 100644 index 000000000..3ee97947c --- /dev/null +++ b/backend/schema/paths/nginx/redirection-hosts/hostID/put.json @@ -0,0 +1,130 @@ +{ + "operationId": "updateRedirectionHost", + "summary": "Update a Redirection Host", + "tags": ["Redirection Hosts"], + "security": [ + { + "BearerAuth": ["redirection_hosts"] + } + ], + "parameters": [ + { + "in": "path", + "name": "hostID", + "schema": { + "type": "integer", + "minimum": 1 + }, + "required": true, + "example": 2 + } + ], + "requestBody": { + "description": "Redirection Host Payload", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "minProperties": 1, + "properties": { + "domain_names": { + "$ref": "../../../../components/redirection-host-object.json#/properties/domain_names" + }, + "forward_http_code": { + "$ref": "../../../../components/redirection-host-object.json#/properties/forward_http_code" + }, + "forward_scheme": { + "$ref": "../../../../components/redirection-host-object.json#/properties/forward_scheme" + }, + "forward_domain_name": { + "$ref": "../../../../components/redirection-host-object.json#/properties/forward_domain_name" + }, + "preserve_path": { + "$ref": "../../../../components/redirection-host-object.json#/properties/preserve_path" + }, + "certificate_id": { + "$ref": "../../../../components/redirection-host-object.json#/properties/certificate_id" + }, + "ssl_forced": { + "$ref": "../../../../components/redirection-host-object.json#/properties/ssl_forced" + }, + "hsts_enabled": { + "$ref": "../../../../components/redirection-host-object.json#/properties/hsts_enabled" + }, + "hsts_subdomains": { + "$ref": "../../../../components/redirection-host-object.json#/properties/hsts_subdomains" + }, + "http2_support": { + "$ref": "../../../../components/redirection-host-object.json#/properties/http2_support" + }, + "block_exploits": { + "$ref": "../../../../components/redirection-host-object.json#/properties/block_exploits" + }, + "advanced_config": { + "$ref": "../../../../components/redirection-host-object.json#/properties/advanced_config" + }, + "meta": { + "$ref": "../../../../components/redirection-host-object.json#/properties/meta" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "200 response", + "content": { + "application/json": { + "examples": { + "default": { + "value": { + "id": 1, + "created_on": "2024-10-09T01:13:12.000Z", + "modified_on": "2024-10-09T01:18:11.000Z", + "owner_user_id": 1, + "domain_names": ["test.example.com"], + "forward_domain_name": "something-else.com", + "preserve_path": 0, + "certificate_id": 0, + "ssl_forced": 0, + "block_exploits": 0, + "advanced_config": "", + "meta": { + "nginx_online": true, + "nginx_err": null + }, + "http2_support": 0, + "enabled": 1, + "hsts_enabled": 0, + "hsts_subdomains": 0, + "forward_scheme": "http", + "forward_http_code": 301, + "owner": { + "id": 1, + "created_on": "2024-10-09T00:59:56.000Z", + "modified_on": "2024-10-09T00:59:56.000Z", + "is_deleted": 0, + "is_disabled": 0, + "email": "admin@example.com", + "name": "Administrator", + "nickname": "Admin", + "avatar": "", + "roles": ["admin"] + }, + "certificate": null, + "use_default_location": true, + "ipv6": true + } + } + }, + "schema": { + "$ref": "../../../../components/redirection-host-object.json" + } + } + } + } + } +} diff --git a/backend/schema/paths/nginx/redirection-hosts/post.json b/backend/schema/paths/nginx/redirection-hosts/post.json new file mode 100644 index 000000000..e8d2fa17b --- /dev/null +++ b/backend/schema/paths/nginx/redirection-hosts/post.json @@ -0,0 +1,115 @@ +{ + "operationId": "createRedirectionHost", + "summary": "Create a Redirection Host", + "tags": ["Redirection Hosts"], + "security": [ + { + "BearerAuth": ["redirection_hosts"] + } + ], + "requestBody": { + "description": "Redirection Host Payload", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "required": ["domain_names", "forward_scheme", "forward_http_code", "forward_domain_name"], + "properties": { + "domain_names": { + "$ref": "../../../components/redirection-host-object.json#/properties/domain_names" + }, + "forward_http_code": { + "$ref": "../../../components/redirection-host-object.json#/properties/forward_http_code" + }, + "forward_scheme": { + "$ref": "../../../components/redirection-host-object.json#/properties/forward_scheme" + }, + "forward_domain_name": { + "$ref": "../../../components/redirection-host-object.json#/properties/forward_domain_name" + }, + "preserve_path": { + "$ref": "../../../components/redirection-host-object.json#/properties/preserve_path" + }, + "certificate_id": { + "$ref": "../../../components/redirection-host-object.json#/properties/certificate_id" + }, + "ssl_forced": { + "$ref": "../../../components/redirection-host-object.json#/properties/ssl_forced" + }, + "hsts_enabled": { + "$ref": "../../../components/redirection-host-object.json#/properties/hsts_enabled" + }, + "hsts_subdomains": { + "$ref": "../../../components/redirection-host-object.json#/properties/hsts_subdomains" + }, + "http2_support": { + "$ref": "../../../components/redirection-host-object.json#/properties/http2_support" + }, + "block_exploits": { + "$ref": "../../../components/redirection-host-object.json#/properties/block_exploits" + }, + "advanced_config": { + "$ref": "../../../components/redirection-host-object.json#/properties/advanced_config" + }, + "meta": { + "$ref": "../../../components/redirection-host-object.json#/properties/meta" + } + } + } + } + } + }, + "responses": { + "201": { + "description": "201 response", + "content": { + "application/json": { + "examples": { + "default": { + "value": { + "id": 1, + "created_on": "2024-10-09T01:13:12.000Z", + "modified_on": "2024-10-09T01:13:12.000Z", + "owner_user_id": 1, + "domain_names": ["test.example.com"], + "forward_domain_name": "something-else.com", + "preserve_path": 0, + "certificate_id": 0, + "ssl_forced": 0, + "block_exploits": 0, + "advanced_config": "", + "meta": {}, + "http2_support": 0, + "enabled": 1, + "hsts_enabled": 0, + "hsts_subdomains": 0, + "forward_scheme": "http", + "forward_http_code": 301, + "certificate": null, + "owner": { + "id": 1, + "created_on": "2024-10-09T00:59:56.000Z", + "modified_on": "2024-10-09T00:59:56.000Z", + "is_deleted": 0, + "is_disabled": 0, + "email": "admin@example.com", + "name": "Administrator", + "nickname": "Admin", + "avatar": "", + "roles": ["admin"] + }, + "use_default_location": true, + "ipv6": true + } + } + }, + "schema": { + "$ref": "../../../components/redirection-host-object.json" + } + } + } + } + } +} diff --git a/backend/schema/paths/nginx/streams/get.json b/backend/schema/paths/nginx/streams/get.json new file mode 100644 index 000000000..5ea97ce39 --- /dev/null +++ b/backend/schema/paths/nginx/streams/get.json @@ -0,0 +1,55 @@ +{ + "operationId": "getStreams", + "summary": "Get all streams", + "tags": ["Streams"], + "security": [ + { + "BearerAuth": ["streams"] + } + ], + "parameters": [ + { + "in": "query", + "name": "expand", + "description": "Expansions", + "schema": { + "type": "string", + "enum": ["access_list", "owner", "certificate"] + } + } + ], + "responses": { + "200": { + "description": "200 response", + "content": { + "application/json": { + "examples": { + "default": { + "value": [ + { + "id": 1, + "created_on": "2024-10-09T02:33:45.000Z", + "modified_on": "2024-10-09T02:33:45.000Z", + "owner_user_id": 1, + "incoming_port": 9090, + "forwarding_host": "router.internal", + "forwarding_port": 80, + "tcp_forwarding": 0, + "udp_forwarding": 0, + "meta": { + "nginx_online": true, + "nginx_err": null + }, + "enabled": 1 + } + ] + } + }, + "schema": { + "$ref": "../../../components/stream-list.json" + } + } + } + } + } +} diff --git a/backend/schema/paths/nginx/streams/post.json b/backend/schema/paths/nginx/streams/post.json new file mode 100644 index 000000000..0610a7273 --- /dev/null +++ b/backend/schema/paths/nginx/streams/post.json @@ -0,0 +1,87 @@ +{ + "operationId": "createStream", + "summary": "Create a Stream", + "tags": ["Streams"], + "security": [ + { + "BearerAuth": ["streams"] + } + ], + "requestBody": { + "description": "Stream Payload", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "required": ["incoming_port", "forwarding_host", "forwarding_port"], + "properties": { + "incoming_port": { + "$ref": "../../../components/stream-object.json#/properties/incoming_port" + }, + "forwarding_host": { + "$ref": "../../../components/stream-object.json#/properties/forwarding_host" + }, + "forwarding_port": { + "$ref": "../../../components/stream-object.json#/properties/forwarding_port" + }, + "tcp_forwarding": { + "$ref": "../../../components/stream-object.json#/properties/tcp_forwarding" + }, + "udp_forwarding": { + "$ref": "../../../components/stream-object.json#/properties/udp_forwarding" + }, + "meta": { + "$ref": "../../../components/stream-object.json#/properties/meta" + } + } + } + } + } + }, + "responses": { + "201": { + "description": "201 response", + "content": { + "application/json": { + "examples": { + "default": { + "value": { + "id": 1, + "created_on": "2024-10-09T02:33:45.000Z", + "modified_on": "2024-10-09T02:33:45.000Z", + "owner_user_id": 1, + "incoming_port": 9090, + "forwarding_host": "router.internal", + "forwarding_port": 80, + "tcp_forwarding": 0, + "udp_forwarding": 0, + "meta": { + "nginx_online": true, + "nginx_err": null + }, + "enabled": 1, + "owner": { + "id": 1, + "created_on": "2024-10-09T02:33:16.000Z", + "modified_on": "2024-10-09T02:33:16.000Z", + "is_deleted": 0, + "is_disabled": 0, + "email": "admin@example.com", + "name": "Administrator", + "nickname": "Admin", + "avatar": "", + "roles": ["admin"] + } + } + } + }, + "schema": { + "$ref": "../../../components/stream-object.json" + } + } + } + } + } +} diff --git a/backend/schema/paths/nginx/streams/streamID/delete.json b/backend/schema/paths/nginx/streams/streamID/delete.json new file mode 100644 index 000000000..3a9685258 --- /dev/null +++ b/backend/schema/paths/nginx/streams/streamID/delete.json @@ -0,0 +1,39 @@ +{ + "operationId": "deleteStream", + "summary": "Delete a Stream", + "tags": ["Streams"], + "security": [ + { + "BearerAuth": ["streams"] + } + ], + "parameters": [ + { + "in": "path", + "name": "streamID", + "schema": { + "type": "integer", + "minimum": 1 + }, + "required": true, + "example": 2 + } + ], + "responses": { + "200": { + "description": "200 response", + "content": { + "application/json": { + "examples": { + "default": { + "value": true + } + }, + "schema": { + "type": "boolean" + } + } + } + } + } +} diff --git a/backend/schema/paths/nginx/streams/streamID/disable/post.json b/backend/schema/paths/nginx/streams/streamID/disable/post.json new file mode 100644 index 000000000..91c58bb80 --- /dev/null +++ b/backend/schema/paths/nginx/streams/streamID/disable/post.json @@ -0,0 +1,59 @@ +{ + "operationId": "disableStream", + "summary": "Disable a Stream", + "tags": ["Streams"], + "security": [ + { + "BearerAuth": ["streams"] + } + ], + "parameters": [ + { + "in": "path", + "name": "streamID", + "schema": { + "type": "integer", + "minimum": 1 + }, + "required": true, + "example": 2 + } + ], + "responses": { + "200": { + "description": "200 response", + "content": { + "application/json": { + "examples": { + "default": { + "value": true + } + }, + "schema": { + "type": "boolean" + } + } + } + }, + "400": { + "description": "400 response", + "content": { + "application/json": { + "examples": { + "default": { + "value": { + "error": { + "code": 400, + "message": "Host is already disabled" + } + } + } + }, + "schema": { + "$ref": "../../../../../components/error-object.json" + } + } + } + } + } +} diff --git a/backend/schema/paths/nginx/streams/streamID/enable/post.json b/backend/schema/paths/nginx/streams/streamID/enable/post.json new file mode 100644 index 000000000..b14a86f86 --- /dev/null +++ b/backend/schema/paths/nginx/streams/streamID/enable/post.json @@ -0,0 +1,59 @@ +{ + "operationId": "enableStream", + "summary": "Enable a Stream", + "tags": ["Streams"], + "security": [ + { + "BearerAuth": ["streams"] + } + ], + "parameters": [ + { + "in": "path", + "name": "streamID", + "schema": { + "type": "integer", + "minimum": 1 + }, + "required": true, + "example": 2 + } + ], + "responses": { + "200": { + "description": "200 response", + "content": { + "application/json": { + "examples": { + "default": { + "value": true + } + }, + "schema": { + "type": "boolean" + } + } + } + }, + "400": { + "description": "400 response", + "content": { + "application/json": { + "examples": { + "default": { + "value": { + "error": { + "code": 400, + "message": "Host is already enabled" + } + } + } + }, + "schema": { + "$ref": "../../../../../components/error-object.json" + } + } + } + } + } +} diff --git a/backend/schema/paths/nginx/streams/streamID/get.json b/backend/schema/paths/nginx/streams/streamID/get.json new file mode 100644 index 000000000..a3371e8b8 --- /dev/null +++ b/backend/schema/paths/nginx/streams/streamID/get.json @@ -0,0 +1,54 @@ +{ + "operationId": "getStream", + "summary": "Get a Stream", + "tags": ["Streams"], + "security": [ + { + "BearerAuth": ["streams"] + } + ], + "parameters": [ + { + "in": "path", + "name": "streamID", + "schema": { + "type": "integer", + "minimum": 1 + }, + "required": true, + "example": 2 + } + ], + "responses": { + "200": { + "description": "200 response", + "content": { + "application/json": { + "examples": { + "default": { + "value": { + "id": 1, + "created_on": "2024-10-09T02:33:45.000Z", + "modified_on": "2024-10-09T02:33:45.000Z", + "owner_user_id": 1, + "incoming_port": 9090, + "forwarding_host": "router.internal", + "forwarding_port": 80, + "tcp_forwarding": 0, + "udp_forwarding": 0, + "meta": { + "nginx_online": true, + "nginx_err": null + }, + "enabled": 1 + } + } + }, + "schema": { + "$ref": "../../../../components/stream-object.json" + } + } + } + } + } +} diff --git a/backend/schema/paths/nginx/streams/streamID/put.json b/backend/schema/paths/nginx/streams/streamID/put.json new file mode 100644 index 000000000..cb85a6917 --- /dev/null +++ b/backend/schema/paths/nginx/streams/streamID/put.json @@ -0,0 +1,145 @@ +{ + "operationId": "updateStream", + "summary": "Update a Stream", + "tags": ["Streams"], + "security": [ + { + "BearerAuth": ["streams"] + } + ], + "parameters": [ + { + "in": "path", + "name": "streamID", + "schema": { + "type": "integer", + "minimum": 1 + }, + "required": true, + "example": 2 + } + ], + "requestBody": { + "description": "Stream Payload", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "minProperties": 1, + "properties": { + "domain_names": { + "$ref": "../../../../components/proxy-host-object.json#/properties/domain_names" + }, + "forward_scheme": { + "$ref": "../../../../components/proxy-host-object.json#/properties/forward_scheme" + }, + "forward_host": { + "$ref": "../../../../components/proxy-host-object.json#/properties/forward_host" + }, + "forward_port": { + "$ref": "../../../../components/proxy-host-object.json#/properties/forward_port" + }, + "certificate_id": { + "$ref": "../../../../components/proxy-host-object.json#/properties/certificate_id" + }, + "ssl_forced": { + "$ref": "../../../../components/proxy-host-object.json#/properties/ssl_forced" + }, + "hsts_enabled": { + "$ref": "../../../../components/proxy-host-object.json#/properties/hsts_enabled" + }, + "hsts_subdomains": { + "$ref": "../../../../components/proxy-host-object.json#/properties/hsts_subdomains" + }, + "http2_support": { + "$ref": "../../../../components/proxy-host-object.json#/properties/http2_support" + }, + "block_exploits": { + "$ref": "../../../../components/proxy-host-object.json#/properties/block_exploits" + }, + "caching_enabled": { + "$ref": "../../../../components/proxy-host-object.json#/properties/caching_enabled" + }, + "allow_websocket_upgrade": { + "$ref": "../../../../components/proxy-host-object.json#/properties/allow_websocket_upgrade" + }, + "access_list_id": { + "$ref": "../../../../components/proxy-host-object.json#/properties/access_list_id" + }, + "advanced_config": { + "$ref": "../../../../components/proxy-host-object.json#/properties/advanced_config" + }, + "enabled": { + "$ref": "../../../../components/proxy-host-object.json#/properties/enabled" + }, + "meta": { + "$ref": "../../../../components/proxy-host-object.json#/properties/meta" + }, + "locations": { + "$ref": "../../../../components/proxy-host-object.json#/properties/locations" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "200 response", + "content": { + "application/json": { + "examples": { + "default": { + "value": { + "id": 1, + "created_on": "2024-10-08T23:23:03.000Z", + "modified_on": "2024-10-08T23:26:37.000Z", + "owner_user_id": 1, + "domain_names": ["test.example.com"], + "forward_host": "192.168.0.10", + "forward_port": 8989, + "access_list_id": 0, + "certificate_id": 0, + "ssl_forced": 0, + "caching_enabled": 0, + "block_exploits": 0, + "advanced_config": "", + "meta": { + "nginx_online": true, + "nginx_err": null + }, + "allow_websocket_upgrade": 0, + "http2_support": 0, + "forward_scheme": "http", + "enabled": 1, + "hsts_enabled": 0, + "hsts_subdomains": 0, + "owner": { + "id": 1, + "created_on": "2024-10-07T22:43:55.000Z", + "modified_on": "2024-10-08T12:52:54.000Z", + "is_deleted": 0, + "is_disabled": 0, + "email": "admin@example.com", + "name": "Administrator", + "nickname": "some guy", + "avatar": "//www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?default=mm", + "roles": ["admin"] + }, + "certificate": null, + "access_list": null, + "use_default_location": true, + "ipv6": true + } + } + }, + "schema": { + "$ref": "../../../../components/stream-object.json" + } + } + } + } + } +} diff --git a/backend/schema/paths/reports/hosts/get.json b/backend/schema/paths/reports/hosts/get.json new file mode 100644 index 000000000..a40ddc723 --- /dev/null +++ b/backend/schema/paths/reports/hosts/get.json @@ -0,0 +1,50 @@ +{ + "operationId": "reportsHosts", + "summary": "Report on Host Statistics", + "tags": ["Reports"], + "security": [ + { + "BearerAuth": ["reports"] + } + ], + "responses": { + "200": { + "description": "200 response", + "content": { + "application/json": { + "examples": { + "default": { + "value": { + "proxy": 20, + "redirection": 1, + "stream": 0, + "dead": 1 + } + } + }, + "schema": { + "type": "object", + "properties": { + "proxy": { + "type": "integer", + "description": "Proxy Hosts Count" + }, + "redirection": { + "type": "integer", + "description": "Redirection Hosts Count" + }, + "stream": { + "type": "integer", + "description": "Streams Count" + }, + "dead": { + "type": "integer", + "description": "404 Hosts Count" + } + } + } + } + } + } + } +} diff --git a/backend/schema/paths/schema/get.json b/backend/schema/paths/schema/get.json new file mode 100644 index 000000000..d435b0042 --- /dev/null +++ b/backend/schema/paths/schema/get.json @@ -0,0 +1,10 @@ +{ + "operationId": "schema", + "summary": "Returns this swagger API schema", + "tags": ["Public"], + "responses": { + "200": { + "description": "200 response" + } + } +} diff --git a/backend/schema/paths/settings/get.json b/backend/schema/paths/settings/get.json new file mode 100644 index 000000000..5d148d8af --- /dev/null +++ b/backend/schema/paths/settings/get.json @@ -0,0 +1,35 @@ +{ + "operationId": "getSettings", + "summary": "Get all settings", + "tags": ["Settings"], + "security": [ + { + "BearerAuth": ["settings"] + } + ], + "responses": { + "200": { + "description": "200 response", + "content": { + "application/json": { + "examples": { + "default": { + "value": [ + { + "id": "default-site", + "name": "Default Site", + "description": "What to show when Nginx is hit with an unknown Host", + "value": "congratulations", + "meta": {} + } + ] + } + }, + "schema": { + "$ref": "../../components/setting-list.json" + } + } + } + } + } +} diff --git a/backend/schema/paths/settings/settingID/get.json b/backend/schema/paths/settings/settingID/get.json new file mode 100644 index 000000000..405b976d2 --- /dev/null +++ b/backend/schema/paths/settings/settingID/get.json @@ -0,0 +1,46 @@ +{ + "operationId": "getSetting", + "summary": "Get a setting", + "tags": ["Settings"], + "security": [ + { + "BearerAuth": ["settings"] + } + ], + "parameters": [ + { + "in": "path", + "name": "settingID", + "schema": { + "type": "string", + "minLength": 1 + }, + "required": true, + "description": "Setting ID", + "example": "default-site" + } + ], + "responses": { + "200": { + "description": "200 response", + "content": { + "application/json": { + "examples": { + "default": { + "value": { + "id": "default-site", + "name": "Default Site", + "description": "What to show when Nginx is hit with an unknown Host", + "value": "congratulations", + "meta": {} + } + } + }, + "schema": { + "$ref": "../../../components/setting-object.json" + } + } + } + } + } +} diff --git a/backend/schema/paths/settings/settingID/put.json b/backend/schema/paths/settings/settingID/put.json new file mode 100644 index 000000000..5888ec056 --- /dev/null +++ b/backend/schema/paths/settings/settingID/put.json @@ -0,0 +1,67 @@ +{ + "operationId": "updateSetting", + "summary": "Update a setting", + "tags": ["Settings"], + "security": [ + { + "BearerAuth": ["settings"] + } + ], + "parameters": [ + { + "in": "path", + "name": "settingID", + "schema": { + "type": "string", + "minLength": 1 + }, + "required": true, + "description": "Setting ID", + "example": "default-site" + } + ], + "requestBody": { + "description": "Setting Payload", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "minProperties": 1, + "properties": { + "value": { + "$ref": "../../../components/setting-object.json#/properties/value" + }, + "meta": { + "$ref": "../../../components/setting-object.json#/properties/meta" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "200 response", + "content": { + "application/json": { + "examples": { + "default": { + "value": { + "id": "default-site", + "name": "Default Site", + "description": "What to show when Nginx is hit with an unknown Host", + "value": "congratulations", + "meta": {} + } + } + }, + "schema": { + "$ref": "../../../components/setting-object.json" + } + } + } + } + } +} diff --git a/backend/schema/paths/tokens/get.json b/backend/schema/paths/tokens/get.json new file mode 100644 index 000000000..859bc61a4 --- /dev/null +++ b/backend/schema/paths/tokens/get.json @@ -0,0 +1,30 @@ +{ + "operationId": "refreshToken", + "summary": "Refresh your access token", + "tags": ["Tokens"], + "security": [ + { + "BearerAuth": ["tokens"] + } + ], + "responses": { + "200": { + "description": "200 response", + "content": { + "application/json": { + "examples": { + "default": { + "value": { + "expires": 1566540510, + "token": "eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.ey...xaHKYr3Kk6MvkUjcC4" + } + } + }, + "schema": { + "$ref": "../../components/token-object.json" + } + } + } + } + } +} diff --git a/backend/schema/paths/tokens/post.json b/backend/schema/paths/tokens/post.json new file mode 100644 index 000000000..dece6b656 --- /dev/null +++ b/backend/schema/paths/tokens/post.json @@ -0,0 +1,55 @@ +{ + "operationId": "requestToken", + "summary": "Request a new access token from credentials", + "tags": ["Tokens"], + "requestBody": { + "description": "Credentials Payload", + "required": true, + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "identity": { + "minLength": 1, + "type": "string" + }, + "scope": { + "minLength": 1, + "type": "string", + "enum": ["user"] + }, + "secret": { + "minLength": 1, + "type": "string" + } + }, + "required": ["identity", "secret"], + "type": "object" + } + } + } + }, + "responses": { + "200": { + "content": { + "application/json": { + "examples": { + "default": { + "value": { + "result": { + "expires": 1566540510, + "token": "eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.ey...xaHKYr3Kk6MvkUjcC4" + } + } + } + }, + "schema": { + "$ref": "../../components/token-object.json" + } + } + }, + "description": "200 response" + } + } +} diff --git a/backend/schema/paths/users/get.json b/backend/schema/paths/users/get.json new file mode 100644 index 000000000..41a0532c3 --- /dev/null +++ b/backend/schema/paths/users/get.json @@ -0,0 +1,74 @@ +{ + "operationId": "getUsers", + "summary": "Get all users", + "tags": ["Users"], + "security": [ + { + "BearerAuth": ["users"] + } + ], + "parameters": [ + { + "in": "query", + "name": "expand", + "description": "Expansions", + "schema": { + "type": "string", + "enum": ["permissions"] + } + } + ], + "responses": { + "200": { + "description": "200 response", + "content": { + "application/json": { + "examples": { + "default": { + "value": [ + { + "id": 1, + "created_on": "2020-01-30T09:36:08.000Z", + "modified_on": "2020-01-30T09:41:04.000Z", + "is_disabled": 0, + "email": "jc@jc21.com", + "name": "Jamie Curnow", + "nickname": "James", + "avatar": "//www.gravatar.com/avatar/6193176330f8d38747f038c170ddb193?default=mm", + "roles": ["admin"] + } + ] + }, + "withPermissions": { + "value": [ + { + "id": 1, + "created_on": "2020-01-30T09:36:08.000Z", + "modified_on": "2020-01-30T09:41:04.000Z", + "is_disabled": 0, + "email": "jc@jc21.com", + "name": "Jamie Curnow", + "nickname": "James", + "avatar": "//www.gravatar.com/avatar/6193176330f8d38747f038c170ddb193?default=mm", + "roles": ["admin"], + "permissions": { + "visibility": "all", + "proxy_hosts": "manage", + "redirection_hosts": "manage", + "dead_hosts": "manage", + "streams": "manage", + "access_lists": "manage", + "certificates": "manage" + } + } + ] + } + }, + "schema": { + "$ref": "../../components/user-list.json" + } + } + } + } + } +} diff --git a/backend/schema/paths/users/post.json b/backend/schema/paths/users/post.json new file mode 100644 index 000000000..1eec1b510 --- /dev/null +++ b/backend/schema/paths/users/post.json @@ -0,0 +1,88 @@ +{ + "operationId": "createUser", + "summary": "Create a User", + "tags": ["Users"], + "security": [ + { + "BearerAuth": ["users"] + } + ], + "requestBody": { + "description": "User Payload", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "required": ["name", "nickname", "email"], + "properties": { + "name": { + "$ref": "../../components/user-object.json#/properties/name" + }, + "nickname": { + "$ref": "../../components/user-object.json#/properties/nickname" + }, + "email": { + "$ref": "../../components/user-object.json#/properties/email" + }, + "roles": { + "$ref": "../../components/user-object.json#/properties/roles" + }, + "is_disabled": { + "$ref": "../../components/user-object.json#/properties/is_disabled" + }, + "auth": { + "type": "object", + "description": "Auth Credentials", + "example": { + "type": "password", + "secret": "bigredhorsebanana" + } + } + } + } + } + } + }, + "responses": { + "201": { + "description": "201 response", + "content": { + "application/json": { + "examples": { + "default": { + "value": { + "id": 2, + "created_on": "2020-01-30T09:41:04.000Z", + "modified_on": "2020-01-30T09:41:04.000Z", + "is_disabled": 0, + "email": "jc@jc21.com", + "name": "Jamie Curnow", + "nickname": "James", + "avatar": "//www.gravatar.com/avatar/6193176330f8d38747f038c170ddb193?default=mm", + "roles": ["admin"], + "permissions": { + "id": 3, + "created_on": "2020-01-30T09:41:04.000Z", + "modified_on": "2020-01-30T09:41:04.000Z", + "user_id": 2, + "visibility": "user", + "proxy_hosts": "manage", + "redirection_hosts": "manage", + "dead_hosts": "manage", + "streams": "manage", + "access_lists": "manage", + "certificates": "manage" + } + } + } + }, + "schema": { + "$ref": "../../components/user-object.json" + } + } + } + } + } +} diff --git a/backend/schema/paths/users/userID/auth/put.json b/backend/schema/paths/users/userID/auth/put.json new file mode 100644 index 000000000..a72f5617c --- /dev/null +++ b/backend/schema/paths/users/userID/auth/put.json @@ -0,0 +1,79 @@ +{ + "operationId": "updateUserAuth", + "summary": "Update a User's Authentication", + "tags": ["Users"], + "security": [ + { + "BearerAuth": ["users"] + } + ], + "parameters": [ + { + "in": "path", + "name": "userID", + "schema": { + "oneOf": [ + { + "type": "string", + "pattern": "^me$" + }, + { + "type": "integer", + "minimum": 1 + } + ] + }, + "required": true, + "description": "User ID or 'me' for yourself", + "example": 2 + } + ], + "requestBody": { + "description": "Auth Payload", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["type", "secret"], + "properties": { + "type": { + "type": "string", + "pattern": "^password$", + "example": "password" + }, + "current": { + "type": "string", + "minLength": 1, + "maxLength": 64, + "example": "changeme" + }, + "secret": { + "type": "string", + "minLength": 8, + "maxLength": 64, + "example": "mySuperN3wP@ssword!" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "200 response", + "content": { + "application/json": { + "examples": { + "default": { + "value": true + } + }, + "schema": { + "type": "boolean" + } + } + } + } + } +} diff --git a/backend/schema/paths/users/userID/delete.json b/backend/schema/paths/users/userID/delete.json new file mode 100644 index 000000000..7d4f36151 --- /dev/null +++ b/backend/schema/paths/users/userID/delete.json @@ -0,0 +1,40 @@ +{ + "operationId": "deleteUser", + "summary": "Delete a User", + "tags": ["Users"], + "security": [ + { + "BearerAuth": ["users"] + } + ], + "parameters": [ + { + "in": "path", + "name": "userID", + "schema": { + "type": "integer", + "minimum": 1 + }, + "required": true, + "description": "User ID", + "example": 2 + } + ], + "responses": { + "200": { + "description": "200 response", + "content": { + "application/json": { + "examples": { + "default": { + "value": true + } + }, + "schema": { + "type": "boolean" + } + } + } + } + } +} diff --git a/backend/schema/paths/users/userID/get.json b/backend/schema/paths/users/userID/get.json new file mode 100644 index 000000000..f79c92943 --- /dev/null +++ b/backend/schema/paths/users/userID/get.json @@ -0,0 +1,58 @@ +{ + "operationId": "getUser", + "summary": "Get a user", + "tags": ["Users"], + "security": [ + { + "BearerAuth": ["users"] + } + ], + "parameters": [ + { + "in": "path", + "name": "userID", + "schema": { + "oneOf": [ + { + "type": "string", + "pattern": "^me$" + }, + { + "type": "integer", + "minimum": 1 + } + ] + }, + "required": true, + "description": "User ID or 'me' for yourself", + "example": 1 + } + ], + "responses": { + "200": { + "description": "200 response", + "content": { + "application/json": { + "examples": { + "default": { + "value": { + "id": 1, + "created_on": "2020-01-30T09:36:08.000Z", + "modified_on": "2020-01-30T09:41:04.000Z", + "is_disabled": 0, + "email": "jc@jc21.com", + "name": "Jamie Curnow", + "nickname": "James", + "avatar": "//www.gravatar.com/avatar/6193176330f8d38747f038c170ddb193?default=mm", + "roles": ["admin"] + } + } + }, + "schema": { + "$ref": "../../../components/user-object.json" + } + } + } + } + } +} diff --git a/backend/schema/paths/users/userID/login/post.json b/backend/schema/paths/users/userID/login/post.json new file mode 100644 index 000000000..5f247b335 --- /dev/null +++ b/backend/schema/paths/users/userID/login/post.json @@ -0,0 +1,73 @@ +{ + "operationId": "loginAsUser", + "summary": "Login as this user", + "tags": ["Users"], + "security": [ + { + "BearerAuth": ["users"] + } + ], + "parameters": [ + { + "in": "path", + "name": "userID", + "schema": { + "type": "integer", + "minimum": 1 + }, + "required": true, + "description": "User ID", + "example": 2 + } + ], + "responses": { + "200": { + "description": "200 response", + "content": { + "application/json": { + "examples": { + "default": { + "value": { + "token": "eyJhbGciOiJSUzI1NiIsInR...16OjT8B3NLyXg", + "expires": "2020-01-31T10:56:23.239Z", + "user": { + "id": 1, + "created_on": "2020-01-30T10:43:44.000Z", + "modified_on": "2020-01-30T10:43:44.000Z", + "is_disabled": 0, + "email": "jc@jc21.com", + "name": "Jamie Curnow", + "nickname": "James", + "avatar": "//www.gravatar.com/avatar/3c8d73f45fd8763f827b964c76e6032a?default=mm", + "roles": ["admin"] + } + } + } + }, + "schema": { + "type": "object", + "description": "Login object", + "required": ["expires", "token", "user"], + "additionalProperties": false, + "properties": { + "expires": { + "description": "Token Expiry Unix Time", + "example": 1566540249, + "minimum": 1, + "type": "number" + }, + "token": { + "description": "JWT Token", + "example": "eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.ey...xaHKYr3Kk6MvkUjcC4", + "type": "string" + }, + "user": { + "$ref": "../../../../components/user-object.json" + } + } + } + } + } + } + } +} diff --git a/backend/schema/paths/users/userID/permissions/put.json b/backend/schema/paths/users/userID/permissions/put.json new file mode 100644 index 000000000..2dcd2aed7 --- /dev/null +++ b/backend/schema/paths/users/userID/permissions/put.json @@ -0,0 +1,51 @@ +{ + "operationId": "updateUserPermissions", + "summary": "Update a User's Permissions", + "tags": ["Users"], + "security": [ + { + "BearerAuth": ["users"] + } + ], + "parameters": [ + { + "in": "path", + "name": "userID", + "schema": { + "type": "integer", + "minimum": 1 + }, + "required": true, + "description": "User ID", + "example": 2 + } + ], + "requestBody": { + "description": "Permissions Payload", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "../../../../components/permission-object.json" + } + } + } + }, + "responses": { + "200": { + "description": "200 response", + "content": { + "application/json": { + "examples": { + "default": { + "value": true + } + }, + "schema": { + "type": "boolean" + } + } + } + } + } +} diff --git a/backend/schema/paths/users/userID/put.json b/backend/schema/paths/users/userID/put.json new file mode 100644 index 000000000..54cb44b44 --- /dev/null +++ b/backend/schema/paths/users/userID/put.json @@ -0,0 +1,88 @@ +{ + "operationId": "updateUser", + "summary": "Update a User", + "tags": ["Users"], + "security": [ + { + "BearerAuth": ["users"] + } + ], + "parameters": [ + { + "in": "path", + "name": "userID", + "schema": { + "oneOf": [ + { + "type": "string", + "pattern": "^me$" + }, + { + "type": "integer", + "minimum": 1 + } + ] + }, + "required": true, + "description": "User ID or 'me' for yourself", + "example": 2 + } + ], + "requestBody": { + "description": "User Payload", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "minProperties": 1, + "properties": { + "name": { + "$ref": "../../../components/user-object.json#/properties/name" + }, + "nickname": { + "$ref": "../../../components/user-object.json#/properties/nickname" + }, + "email": { + "$ref": "../../../components/user-object.json#/properties/email" + }, + "roles": { + "$ref": "../../../components/user-object.json#/properties/roles" + }, + "is_disabled": { + "$ref": "../../../components/user-object.json#/properties/is_disabled" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "200 response", + "content": { + "application/json": { + "examples": { + "default": { + "value": { + "id": 2, + "created_on": "2020-01-30T09:36:08.000Z", + "modified_on": "2020-01-30T09:41:04.000Z", + "is_disabled": 0, + "email": "jc@jc21.com", + "name": "Jamie Curnow", + "nickname": "James", + "avatar": "//www.gravatar.com/avatar/6193176330f8d38747f038c170ddb193?default=mm", + "roles": ["admin"] + } + } + }, + "schema": { + "$ref": "../../../components/user-object.json" + } + } + } + } + } +} diff --git a/backend/schema/swagger.json b/backend/schema/swagger.json new file mode 100644 index 000000000..9c00fa634 --- /dev/null +++ b/backend/schema/swagger.json @@ -0,0 +1,265 @@ +{ + "openapi": "3.0.0", + "info": { + "title": "Nginx Proxy Manager API", + "version": "2.x.x" + }, + "servers": [ + { + "url": "http://127.0.0.1:81/api" + } + ], + "paths": { + "/": { + "get": { + "$ref": "./paths/get.json" + } + }, + "/audit-log": { + "get": { + "$ref": "./paths/audit-log/get.json" + } + }, + "/nginx/access-lists": { + "get": { + "$ref": "./paths/nginx/access-lists/get.json" + }, + "post": { + "$ref": "./paths/nginx/access-lists/post.json" + } + }, + "/nginx/access-lists/{listID}": { + "get": { + "$ref": "./paths/nginx/access-lists/listID/get.json" + }, + "put": { + "$ref": "./paths/nginx/access-lists/listID/put.json" + }, + "delete": { + "$ref": "./paths/nginx/access-lists/listID/delete.json" + } + }, + "/nginx/certificates": { + "get": { + "$ref": "./paths/nginx/certificates/get.json" + }, + "post": { + "$ref": "./paths/nginx/certificates/post.json" + } + }, + "/nginx/certificates/validate": { + "post": { + "$ref": "./paths/nginx/certificates/validate/post.json" + } + }, + "/nginx/certificates/test-http": { + "get": { + "$ref": "./paths/nginx/certificates/test-http/get.json" + } + }, + "/nginx/certificates/{certID}": { + "get": { + "$ref": "./paths/nginx/certificates/certID/get.json" + }, + "delete": { + "$ref": "./paths/nginx/certificates/certID/delete.json" + } + }, + "/nginx/certificates/{certID}/download": { + "get": { + "$ref": "./paths/nginx/certificates/certID/download/get.json" + } + }, + "/nginx/certificates/{certID}/renew": { + "post": { + "$ref": "./paths/nginx/certificates/certID/renew/post.json" + } + }, + "/nginx/certificates/{certID}/upload": { + "post": { + "$ref": "./paths/nginx/certificates/certID/upload/post.json" + } + }, + "/nginx/proxy-hosts": { + "get": { + "$ref": "./paths/nginx/proxy-hosts/get.json" + }, + "post": { + "$ref": "./paths/nginx/proxy-hosts/post.json" + } + }, + "/nginx/proxy-hosts/{hostID}": { + "get": { + "$ref": "./paths/nginx/proxy-hosts/hostID/get.json" + }, + "put": { + "$ref": "./paths/nginx/proxy-hosts/hostID/put.json" + }, + "delete": { + "$ref": "./paths/nginx/proxy-hosts/hostID/delete.json" + } + }, + "/nginx/proxy-hosts/{hostID}/enable": { + "post": { + "$ref": "./paths/nginx/proxy-hosts/hostID/enable/post.json" + } + }, + "/nginx/proxy-hosts/{hostID}/disable": { + "post": { + "$ref": "./paths/nginx/proxy-hosts/hostID/disable/post.json" + } + }, + "/nginx/redirection-hosts": { + "get": { + "$ref": "./paths/nginx/redirection-hosts/get.json" + }, + "post": { + "$ref": "./paths/nginx/redirection-hosts/post.json" + } + }, + "/nginx/redirection-hosts/{hostID}": { + "get": { + "$ref": "./paths/nginx/redirection-hosts/hostID/get.json" + }, + "put": { + "$ref": "./paths/nginx/redirection-hosts/hostID/put.json" + }, + "delete": { + "$ref": "./paths/nginx/redirection-hosts/hostID/delete.json" + } + }, + "/nginx/redirection-hosts/{hostID}/enable": { + "post": { + "$ref": "./paths/nginx/redirection-hosts/hostID/enable/post.json" + } + }, + "/nginx/redirection-hosts/{hostID}/disable": { + "post": { + "$ref": "./paths/nginx/redirection-hosts/hostID/disable/post.json" + } + }, + "/nginx/dead-hosts": { + "get": { + "$ref": "./paths/nginx/dead-hosts/get.json" + }, + "post": { + "$ref": "./paths/nginx/dead-hosts/post.json" + } + }, + "/nginx/dead-hosts/{hostID}": { + "get": { + "$ref": "./paths/nginx/dead-hosts/hostID/get.json" + }, + "put": { + "$ref": "./paths/nginx/dead-hosts/hostID/put.json" + }, + "delete": { + "$ref": "./paths/nginx/dead-hosts/hostID/delete.json" + } + }, + "/nginx/dead-hosts/{hostID}/enable": { + "post": { + "$ref": "./paths/nginx/dead-hosts/hostID/enable/post.json" + } + }, + "/nginx/dead-hosts/{hostID}/disable": { + "post": { + "$ref": "./paths/nginx/dead-hosts/hostID/disable/post.json" + } + }, + "/nginx/streams": { + "get": { + "$ref": "./paths/nginx/streams/get.json" + }, + "post": { + "$ref": "./paths/nginx/streams/post.json" + } + }, + "/nginx/streams/{streamID}": { + "get": { + "$ref": "./paths/nginx/streams/streamID/get.json" + }, + "put": { + "$ref": "./paths/nginx/streams/streamID/put.json" + }, + "delete": { + "$ref": "./paths/nginx/streams/streamID/delete.json" + } + }, + "/nginx/streams/{streamID}/enable": { + "post": { + "$ref": "./paths/nginx/streams/streamID/enable/post.json" + } + }, + "/nginx/streams/{streamID}/disable": { + "post": { + "$ref": "./paths/nginx/streams/streamID/disable/post.json" + } + }, + "/reports/hosts": { + "get": { + "$ref": "./paths/reports/hosts/get.json" + } + }, + "/schema": { + "get": { + "$ref": "./paths/schema/get.json" + } + }, + "/settings": { + "get": { + "$ref": "./paths/settings/get.json" + } + }, + "/settings/{settingID}": { + "get": { + "$ref": "./paths/settings/settingID/get.json" + }, + "put": { + "$ref": "./paths/settings/settingID/put.json" + } + }, + "/tokens": { + "get": { + "$ref": "./paths/tokens/get.json" + }, + "post": { + "$ref": "./paths/tokens/post.json" + } + }, + "/users": { + "get": { + "$ref": "./paths/users/get.json" + }, + "post": { + "$ref": "./paths/users/post.json" + } + }, + "/users/{userID}": { + "get": { + "$ref": "./paths/users/userID/get.json" + }, + "put": { + "$ref": "./paths/users/userID/put.json" + }, + "delete": { + "$ref": "./paths/users/userID/delete.json" + } + }, + "/users/{userID}/auth": { + "put": { + "$ref": "./paths/users/userID/auth/put.json" + } + }, + "/users/{userID}/permissions": { + "put": { + "$ref": "./paths/users/userID/permissions/put.json" + } + }, + "/users/{userID}/login": { + "post": { + "$ref": "./paths/users/userID/login/post.json" + } + } + } +} diff --git a/backend/yarn.lock b/backend/yarn.lock index af2095496..6346c14ce 100644 --- a/backend/yarn.lock +++ b/backend/yarn.lock @@ -11,6 +11,15 @@ call-me-maybe "^1.0.1" js-yaml "^3.13.1" +"@apidevtools/json-schema-ref-parser@^11.7.0": + version "11.7.0" + resolved "https://registry.yarnpkg.com/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-11.7.0.tgz#228d72018a0e7cbee744b677eaa01a8968f302d9" + integrity sha512-pRrmXMCwnmrkS3MLgAIW5dXRzeTv6GLjkjb4HmxNnvAKXN1Nfzp4KmGADBQvlVUcqi+a5D+hfGDLLnd5NnYxog== + dependencies: + "@jsdevtools/ono" "^7.1.3" + "@types/json-schema" "^7.0.15" + js-yaml "^4.1.0" + "@eslint-community/eslint-utils@^4.2.0": version "4.3.0" resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.3.0.tgz#a556790523a351b4e47e9d385f47265eaaf9780a" @@ -67,7 +76,7 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== -"@jsdevtools/ono@^7.1.0": +"@jsdevtools/ono@^7.1.0", "@jsdevtools/ono@^7.1.3": version "7.1.3" resolved "https://registry.yarnpkg.com/@jsdevtools/ono/-/ono-7.1.3.tgz#9df03bbd7c696a5c58885c34aa06da41c8543796" integrity sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg== @@ -146,6 +155,11 @@ resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0" integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ== +"@types/json-schema@^7.0.15": + version "7.0.15" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" + integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== + abbrev@1: version "1.1.1" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" diff --git a/docker/docker-compose.dev.yml b/docker/docker-compose.dev.yml index 14ca2f7a7..8092a33e4 100644 --- a/docker/docker-compose.dev.yml +++ b/docker/docker-compose.dev.yml @@ -54,6 +54,17 @@ services: volumes: - db_data:/var/lib/mysql + swagger: + image: swaggerapi/swagger-ui:latest + container_name: npm_swagger + ports: + - 3082:80 + environment: + URL: "http://npm:81/api/schema" + PORT: '80' + depends_on: + - npm + volumes: npm_data: name: npm_core_data From 4572b205c912db498706e9a3e8f1891c94129c88 Mon Sep 17 00:00:00 2001 From: Jamie Curnow Date: Thu, 10 Oct 2024 15:53:11 +1000 Subject: [PATCH 2/5] Openapi Schema improvements - Return proper booleans in api responses - Update jsonschemavalidation to latest draft --- backend/doc/api.swagger.json | 1456 ----------------- backend/internal/proxy-host.js | 2 +- backend/lib/access.js | 13 +- backend/lib/access/permissions.json | 1 - backend/lib/access/roles.json | 1 - backend/lib/helpers.js | 18 + backend/lib/validator/api.js | 17 +- backend/lib/validator/index.js | 15 +- backend/models/access_list.js | 17 + backend/models/auth.js | 25 +- backend/models/certificate.js | 23 +- backend/models/dead_host.js | 16 + backend/models/proxy_host.js | 23 + backend/models/redirection_host.js | 19 + backend/models/stream.js | 25 +- backend/models/user.js | 16 + backend/package.json | 10 +- backend/routes/audit-log.js | 4 +- backend/routes/nginx/access_lists.js | 8 +- backend/routes/nginx/certificates.js | 8 +- backend/routes/nginx/dead_hosts.js | 8 +- backend/routes/nginx/proxy_hosts.js | 8 +- backend/routes/nginx/redirection_hosts.js | 8 +- backend/routes/nginx/streams.js | 8 +- backend/routes/users.js | 8 +- backend/schema/common.json | 19 +- .../schema/components/access-list-object.json | 8 +- .../schema/components/audit-log-object.json | 10 +- .../schema/components/certificate-object.json | 16 +- .../schema/components/dead-host-object.json | 22 +- .../schema/components/proxy-host-object.json | 46 +- .../components/redirection-host-object.json | 24 +- backend/schema/components/stream-object.json | 10 +- backend/schema/components/user-object.json | 8 +- .../schema/paths/nginx/access-lists/get.json | 4 +- .../paths/nginx/access-lists/listID/get.json | 2 +- .../paths/nginx/access-lists/listID/put.json | 8 +- .../schema/paths/nginx/access-lists/post.json | 8 +- .../nginx/certificates/certID/renew/post.json | 2 +- .../schema/paths/nginx/certificates/post.json | 2 +- .../schema/paths/nginx/dead-hosts/get.json | 10 +- .../paths/nginx/dead-hosts/hostID/get.json | 10 +- .../paths/nginx/dead-hosts/hostID/put.json | 14 +- .../schema/paths/nginx/dead-hosts/post.json | 14 +- .../schema/paths/nginx/proxy-hosts/get.json | 16 +- .../paths/nginx/proxy-hosts/hostID/get.json | 16 +- .../paths/nginx/proxy-hosts/hostID/put.json | 20 +- .../schema/paths/nginx/proxy-hosts/post.json | 20 +- .../paths/nginx/redirection-hosts/get.json | 14 +- .../nginx/redirection-hosts/hostID/get.json | 14 +- .../nginx/redirection-hosts/hostID/put.json | 18 +- .../paths/nginx/redirection-hosts/post.json | 18 +- backend/schema/paths/nginx/streams/get.json | 6 +- backend/schema/paths/nginx/streams/post.json | 10 +- .../paths/nginx/streams/streamID/get.json | 6 +- .../paths/nginx/streams/streamID/put.json | 20 +- backend/schema/paths/users/get.json | 4 +- backend/schema/paths/users/post.json | 2 +- backend/schema/paths/users/userID/get.json | 2 +- .../schema/paths/users/userID/login/post.json | 2 +- backend/schema/paths/users/userID/put.json | 2 +- backend/schema/swagger.json | 2 +- backend/validate-schema.js | 16 + backend/yarn.lock | 80 +- test/cypress/e2e/api/Health.cy.js | 2 +- test/cypress/e2e/api/Hosts.cy.js | 2 +- test/cypress/plugins/backendApi/logger.js | 9 +- test/package.json | 17 +- test/yarn.lock | 634 +++---- 69 files changed, 863 insertions(+), 2083 deletions(-) delete mode 100644 backend/doc/api.swagger.json create mode 100644 backend/validate-schema.js diff --git a/backend/doc/api.swagger.json b/backend/doc/api.swagger.json deleted file mode 100644 index 3fa19fc4b..000000000 --- a/backend/doc/api.swagger.json +++ /dev/null @@ -1,1456 +0,0 @@ -{ - "openapi": "3.0.0", - "info": { - "title": "Nginx Proxy Manager API", - "version": "2.x.x" - }, - "servers": [ - { - "url": "http://127.0.0.1:81/api" - } - ], - "paths": { - "/": { - "get": { - "operationId": "health", - "summary": "Returns the API health status", - "responses": { - "200": { - "description": "200 response", - "content": { - "application/json": { - "examples": { - "default": { - "value": { - "status": "OK", - "version": { - "major": 2, - "minor": 1, - "revision": 0 - } - } - } - }, - "schema": { - "$ref": "#/components/schemas/HealthObject" - } - } - } - } - } - } - }, - "/nginx/proxy-hosts": { - "get": { - "operationId": "getProxyHosts", - "summary": "Get all proxy hosts", - "tags": ["Proxy Hosts"], - "security": [ - { - "BearerAuth": ["users"] - } - ], - "parameters": [ - { - "in": "query", - "name": "expand", - "description": "Expansions", - "schema": { - "type": "string", - "enum": ["access_list", "owner", "certificate"] - } - } - ], - "responses": { - "200": { - "description": "200 response", - "content": { - "application/json": { - "examples": { - "default": { - "value": [ - { - "id": 1, - "created_on": "2023-03-30T01:12:23.000Z", - "modified_on": "2023-03-30T02:15:40.000Z", - "owner_user_id": 1, - "domain_names": ["aasdasdad"], - "forward_host": "asdasd", - "forward_port": 80, - "access_list_id": 0, - "certificate_id": 0, - "ssl_forced": 0, - "caching_enabled": 0, - "block_exploits": 0, - "advanced_config": "sdfsdfsdf", - "meta": { - "letsencrypt_agree": false, - "dns_challenge": false, - "nginx_online": false, - "nginx_err": "Command failed: /usr/sbin/nginx -t -g \"error_log off;\"\nnginx: [emerg] unknown directive \"sdfsdfsdf\" in /data/nginx/proxy_host/1.conf:37\nnginx: configuration file /etc/nginx/nginx.conf test failed\n" - }, - "allow_websocket_upgrade": 0, - "http2_support": 0, - "forward_scheme": "http", - "enabled": 1, - "locations": [], - "hsts_enabled": 0, - "hsts_subdomains": 0, - "owner": { - "id": 1, - "created_on": "2023-03-30T01:11:50.000Z", - "modified_on": "2023-03-30T01:11:50.000Z", - "is_deleted": 0, - "is_disabled": 0, - "email": "admin@example.com", - "name": "Administrator", - "nickname": "Admin", - "avatar": "", - "roles": ["admin"] - }, - "access_list": null, - "certificate": null - }, - { - "id": 2, - "created_on": "2023-03-30T02:11:49.000Z", - "modified_on": "2023-03-30T02:11:49.000Z", - "owner_user_id": 1, - "domain_names": ["test.example.com"], - "forward_host": "1.1.1.1", - "forward_port": 80, - "access_list_id": 0, - "certificate_id": 0, - "ssl_forced": 0, - "caching_enabled": 0, - "block_exploits": 0, - "advanced_config": "", - "meta": { - "letsencrypt_agree": false, - "dns_challenge": false, - "nginx_online": true, - "nginx_err": null - }, - "allow_websocket_upgrade": 0, - "http2_support": 0, - "forward_scheme": "http", - "enabled": 1, - "locations": [], - "hsts_enabled": 0, - "hsts_subdomains": 0, - "owner": { - "id": 1, - "created_on": "2023-03-30T01:11:50.000Z", - "modified_on": "2023-03-30T01:11:50.000Z", - "is_deleted": 0, - "is_disabled": 0, - "email": "admin@example.com", - "name": "Administrator", - "nickname": "Admin", - "avatar": "", - "roles": ["admin"] - }, - "access_list": null, - "certificate": null - } - ] - } - }, - "schema": { - "$ref": "#/components/schemas/ProxyHostsList" - } - } - } - } - } - }, - "post": { - "operationId": "createProxyHost", - "summary": "Create a Proxy Host", - "tags": ["Proxy Hosts"], - "security": [ - { - "BearerAuth": ["users"] - } - ], - "parameters": [ - { - "in": "body", - "name": "proxyhost", - "description": "Proxy Host Payload", - "required": true, - "schema": { - "$ref": "#/components/schemas/ProxyHostObject" - } - } - ], - "responses": { - "201": { - "description": "201 response", - "content": { - "application/json": { - "examples": { - "default": { - "value": { - "id": 3, - "created_on": "2023-03-30T02:31:27.000Z", - "modified_on": "2023-03-30T02:31:27.000Z", - "owner_user_id": 1, - "domain_names": ["test2.example.com"], - "forward_host": "1.1.1.1", - "forward_port": 80, - "access_list_id": 0, - "certificate_id": 0, - "ssl_forced": 0, - "caching_enabled": 0, - "block_exploits": 0, - "advanced_config": "", - "meta": { - "letsencrypt_agree": false, - "dns_challenge": false - }, - "allow_websocket_upgrade": 0, - "http2_support": 0, - "forward_scheme": "http", - "enabled": 1, - "locations": [], - "hsts_enabled": 0, - "hsts_subdomains": 0, - "certificate": null, - "owner": { - "id": 1, - "created_on": "2023-03-30T01:11:50.000Z", - "modified_on": "2023-03-30T01:11:50.000Z", - "is_deleted": 0, - "is_disabled": 0, - "email": "admin@example.com", - "name": "Administrator", - "nickname": "Admin", - "avatar": "", - "roles": ["admin"] - }, - "access_list": null, - "use_default_location": true, - "ipv6": true - } - } - }, - "schema": { - "$ref": "#/components/schemas/ProxyHostObject" - } - } - } - } - } - } - }, - "/schema": { - "get": { - "operationId": "schema", - "responses": { - "200": { - "description": "200 response" - } - }, - "summary": "Returns this swagger API schema" - } - }, - "/tokens": { - "get": { - "operationId": "refreshToken", - "summary": "Refresh your access token", - "tags": ["Tokens"], - "security": [ - { - "BearerAuth": ["tokens"] - } - ], - "responses": { - "200": { - "description": "200 response", - "content": { - "application/json": { - "examples": { - "default": { - "value": { - "expires": 1566540510, - "token": "eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.ey...xaHKYr3Kk6MvkUjcC4" - } - } - }, - "schema": { - "$ref": "#/components/schemas/TokenObject" - } - } - } - } - } - }, - "post": { - "operationId": "requestToken", - "parameters": [ - { - "description": "Credentials Payload", - "in": "body", - "name": "credentials", - "required": true, - "schema": { - "additionalProperties": false, - "properties": { - "identity": { - "minLength": 1, - "type": "string" - }, - "scope": { - "minLength": 1, - "type": "string", - "enum": ["user"] - }, - "secret": { - "minLength": 1, - "type": "string" - } - }, - "required": ["identity", "secret"], - "type": "object" - } - } - ], - "responses": { - "200": { - "content": { - "application/json": { - "examples": { - "default": { - "value": { - "result": { - "expires": 1566540510, - "token": "eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.ey...xaHKYr3Kk6MvkUjcC4" - } - } - } - }, - "schema": { - "$ref": "#/components/schemas/TokenObject" - } - } - }, - "description": "200 response" - } - }, - "summary": "Request a new access token from credentials", - "tags": ["Tokens"] - } - }, - "/settings": { - "get": { - "operationId": "getSettings", - "summary": "Get all settings", - "tags": ["Settings"], - "security": [ - { - "BearerAuth": ["settings"] - } - ], - "responses": { - "200": { - "description": "200 response", - "content": { - "application/json": { - "examples": { - "default": { - "value": [ - { - "id": "default-site", - "name": "Default Site", - "description": "What to show when Nginx is hit with an unknown Host", - "value": "congratulations", - "meta": {} - } - ] - } - }, - "schema": { - "$ref": "#/components/schemas/SettingsList" - } - } - } - } - } - } - }, - "/settings/{settingID}": { - "get": { - "operationId": "getSetting", - "summary": "Get a setting", - "tags": ["Settings"], - "security": [ - { - "BearerAuth": ["settings"] - } - ], - "parameters": [ - { - "in": "path", - "name": "settingID", - "schema": { - "type": "string", - "minLength": 1 - }, - "required": true, - "description": "Setting ID", - "example": "default-site" - } - ], - "responses": { - "200": { - "description": "200 response", - "content": { - "application/json": { - "examples": { - "default": { - "value": { - "id": "default-site", - "name": "Default Site", - "description": "What to show when Nginx is hit with an unknown Host", - "value": "congratulations", - "meta": {} - } - } - }, - "schema": { - "$ref": "#/components/schemas/SettingObject" - } - } - } - } - } - }, - "put": { - "operationId": "updateSetting", - "summary": "Update a setting", - "tags": ["Settings"], - "security": [ - { - "BearerAuth": ["settings"] - } - ], - "parameters": [ - { - "in": "path", - "name": "settingID", - "schema": { - "type": "string", - "minLength": 1 - }, - "required": true, - "description": "Setting ID", - "example": "default-site" - }, - { - "in": "body", - "name": "setting", - "description": "Setting Payload", - "required": true, - "schema": { - "$ref": "#/components/schemas/SettingObject" - } - } - ], - "responses": { - "200": { - "description": "200 response", - "content": { - "application/json": { - "examples": { - "default": { - "value": { - "id": "default-site", - "name": "Default Site", - "description": "What to show when Nginx is hit with an unknown Host", - "value": "congratulations", - "meta": {} - } - } - }, - "schema": { - "$ref": "#/components/schemas/SettingObject" - } - } - } - } - } - } - }, - "/users": { - "get": { - "operationId": "getUsers", - "summary": "Get all users", - "tags": ["Users"], - "security": [ - { - "BearerAuth": ["users"] - } - ], - "parameters": [ - { - "in": "query", - "name": "expand", - "description": "Expansions", - "schema": { - "type": "string", - "enum": ["permissions"] - } - } - ], - "responses": { - "200": { - "description": "200 response", - "content": { - "application/json": { - "examples": { - "default": { - "value": [ - { - "id": 1, - "created_on": "2020-01-30T09:36:08.000Z", - "modified_on": "2020-01-30T09:41:04.000Z", - "is_disabled": 0, - "email": "jc@jc21.com", - "name": "Jamie Curnow", - "nickname": "James", - "avatar": "//www.gravatar.com/avatar/6193176330f8d38747f038c170ddb193?default=mm", - "roles": ["admin"] - } - ] - }, - "withPermissions": { - "value": [ - { - "id": 1, - "created_on": "2020-01-30T09:36:08.000Z", - "modified_on": "2020-01-30T09:41:04.000Z", - "is_disabled": 0, - "email": "jc@jc21.com", - "name": "Jamie Curnow", - "nickname": "James", - "avatar": "//www.gravatar.com/avatar/6193176330f8d38747f038c170ddb193?default=mm", - "roles": ["admin"], - "permissions": { - "visibility": "all", - "proxy_hosts": "manage", - "redirection_hosts": "manage", - "dead_hosts": "manage", - "streams": "manage", - "access_lists": "manage", - "certificates": "manage" - } - } - ] - } - }, - "schema": { - "$ref": "#/components/schemas/UsersList" - } - } - } - } - } - }, - "post": { - "operationId": "createUser", - "summary": "Create a User", - "tags": ["Users"], - "security": [ - { - "BearerAuth": ["users"] - } - ], - "parameters": [ - { - "in": "body", - "name": "user", - "description": "User Payload", - "required": true, - "schema": { - "$ref": "#/components/schemas/UserObject" - } - } - ], - "responses": { - "201": { - "description": "201 response", - "content": { - "application/json": { - "examples": { - "default": { - "value": { - "id": 2, - "created_on": "2020-01-30T09:36:08.000Z", - "modified_on": "2020-01-30T09:41:04.000Z", - "is_disabled": 0, - "email": "jc@jc21.com", - "name": "Jamie Curnow", - "nickname": "James", - "avatar": "//www.gravatar.com/avatar/6193176330f8d38747f038c170ddb193?default=mm", - "roles": ["admin"], - "permissions": { - "visibility": "all", - "proxy_hosts": "manage", - "redirection_hosts": "manage", - "dead_hosts": "manage", - "streams": "manage", - "access_lists": "manage", - "certificates": "manage" - } - } - } - }, - "schema": { - "$ref": "#/components/schemas/UserObject" - } - } - } - } - } - } - }, - "/users/{userID}": { - "get": { - "operationId": "getUser", - "summary": "Get a user", - "tags": ["Users"], - "security": [ - { - "BearerAuth": ["users"] - } - ], - "parameters": [ - { - "in": "path", - "name": "userID", - "schema": { - "oneOf": [ - { - "type": "string", - "pattern": "^me$" - }, - { - "type": "integer", - "minimum": 1 - } - ] - }, - "required": true, - "description": "User ID or 'me' for yourself", - "example": 1 - } - ], - "responses": { - "200": { - "description": "200 response", - "content": { - "application/json": { - "examples": { - "default": { - "value": { - "id": 1, - "created_on": "2020-01-30T09:36:08.000Z", - "modified_on": "2020-01-30T09:41:04.000Z", - "is_disabled": 0, - "email": "jc@jc21.com", - "name": "Jamie Curnow", - "nickname": "James", - "avatar": "//www.gravatar.com/avatar/6193176330f8d38747f038c170ddb193?default=mm", - "roles": ["admin"] - } - } - }, - "schema": { - "$ref": "#/components/schemas/UserObject" - } - } - } - } - } - }, - "put": { - "operationId": "updateUser", - "summary": "Update a User", - "tags": ["Users"], - "security": [ - { - "BearerAuth": ["users"] - } - ], - "parameters": [ - { - "in": "path", - "name": "userID", - "schema": { - "oneOf": [ - { - "type": "string", - "pattern": "^me$" - }, - { - "type": "integer", - "minimum": 1 - } - ] - }, - "required": true, - "description": "User ID or 'me' for yourself", - "example": 2 - }, - { - "in": "body", - "name": "user", - "description": "User Payload", - "required": true, - "schema": { - "$ref": "#/components/schemas/UserObject" - } - } - ], - "responses": { - "200": { - "description": "200 response", - "content": { - "application/json": { - "examples": { - "default": { - "value": { - "id": 2, - "created_on": "2020-01-30T09:36:08.000Z", - "modified_on": "2020-01-30T09:41:04.000Z", - "is_disabled": 0, - "email": "jc@jc21.com", - "name": "Jamie Curnow", - "nickname": "James", - "avatar": "//www.gravatar.com/avatar/6193176330f8d38747f038c170ddb193?default=mm", - "roles": ["admin"] - } - } - }, - "schema": { - "$ref": "#/components/schemas/UserObject" - } - } - } - } - } - }, - "delete": { - "operationId": "deleteUser", - "summary": "Delete a User", - "tags": ["Users"], - "security": [ - { - "BearerAuth": ["users"] - } - ], - "parameters": [ - { - "in": "path", - "name": "userID", - "schema": { - "type": "integer", - "minimum": 1 - }, - "required": true, - "description": "User ID", - "example": 2 - } - ], - "responses": { - "200": { - "description": "200 response", - "content": { - "application/json": { - "examples": { - "default": { - "value": true - } - }, - "schema": { - "type": "boolean" - } - } - } - } - } - } - }, - "/users/{userID}/auth": { - "put": { - "operationId": "updateUserAuth", - "summary": "Update a User's Authentication", - "tags": ["Users"], - "security": [ - { - "BearerAuth": ["users"] - } - ], - "parameters": [ - { - "in": "path", - "name": "userID", - "schema": { - "oneOf": [ - { - "type": "string", - "pattern": "^me$" - }, - { - "type": "integer", - "minimum": 1 - } - ] - }, - "required": true, - "description": "User ID or 'me' for yourself", - "example": 2 - }, - { - "in": "body", - "name": "user", - "description": "User Payload", - "required": true, - "schema": { - "$ref": "#/components/schemas/AuthObject" - } - } - ], - "responses": { - "200": { - "description": "200 response", - "content": { - "application/json": { - "examples": { - "default": { - "value": true - } - }, - "schema": { - "type": "boolean" - } - } - } - } - } - } - }, - "/users/{userID}/permissions": { - "put": { - "operationId": "updateUserPermissions", - "summary": "Update a User's Permissions", - "tags": ["Users"], - "security": [ - { - "BearerAuth": ["users"] - } - ], - "parameters": [ - { - "in": "path", - "name": "userID", - "schema": { - "type": "integer", - "minimum": 1 - }, - "required": true, - "description": "User ID", - "example": 2 - }, - { - "in": "body", - "name": "user", - "description": "Permissions Payload", - "required": true, - "schema": { - "$ref": "#/components/schemas/PermissionsObject" - } - } - ], - "responses": { - "200": { - "description": "200 response", - "content": { - "application/json": { - "examples": { - "default": { - "value": true - } - }, - "schema": { - "type": "boolean" - } - } - } - } - } - } - }, - "/users/{userID}/login": { - "put": { - "operationId": "loginAsUser", - "summary": "Login as this user", - "tags": ["Users"], - "security": [ - { - "BearerAuth": ["users"] - } - ], - "parameters": [ - { - "in": "path", - "name": "userID", - "schema": { - "type": "integer", - "minimum": 1 - }, - "required": true, - "description": "User ID", - "example": 2 - } - ], - "responses": { - "200": { - "description": "200 response", - "content": { - "application/json": { - "examples": { - "default": { - "value": { - "token": "eyJhbGciOiJSUzI1NiIsInR...16OjT8B3NLyXg", - "expires": "2020-01-31T10:56:23.239Z", - "user": { - "id": 1, - "created_on": "2020-01-30T10:43:44.000Z", - "modified_on": "2020-01-30T10:43:44.000Z", - "is_disabled": 0, - "email": "jc@jc21.com", - "name": "Jamie Curnow", - "nickname": "James", - "avatar": "//www.gravatar.com/avatar/3c8d73f45fd8763f827b964c76e6032a?default=mm", - "roles": ["admin"] - } - } - } - }, - "schema": { - "type": "object", - "description": "Login object", - "required": ["expires", "token", "user"], - "additionalProperties": false, - "properties": { - "expires": { - "description": "Token Expiry Unix Time", - "example": 1566540249, - "minimum": 1, - "type": "number" - }, - "token": { - "description": "JWT Token", - "example": "eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.ey...xaHKYr3Kk6MvkUjcC4", - "type": "string" - }, - "user": { - "$ref": "#/components/schemas/UserObject" - } - } - } - } - } - } - } - } - }, - "/reports/hosts": { - "get": { - "operationId": "reportsHosts", - "summary": "Report on Host Statistics", - "tags": ["Reports"], - "security": [ - { - "BearerAuth": ["reports"] - } - ], - "responses": { - "200": { - "description": "200 response", - "content": { - "application/json": { - "examples": { - "default": { - "value": { - "proxy": 20, - "redirection": 1, - "stream": 0, - "dead": 1 - } - } - }, - "schema": { - "$ref": "#/components/schemas/HostReportObject" - } - } - } - } - } - } - }, - "/audit-log": { - "get": { - "operationId": "getAuditLog", - "summary": "Get Audit Log", - "tags": ["Audit Log"], - "security": [ - { - "BearerAuth": ["audit-log"] - } - ], - "responses": { - "200": { - "description": "200 response", - "content": { - "application/json": { - "examples": { - "default": { - "value": { - "proxy": 20, - "redirection": 1, - "stream": 0, - "dead": 1 - } - } - }, - "schema": { - "$ref": "#/components/schemas/HostReportObject" - } - } - } - } - } - } - } - }, - "components": { - "securitySchemes": { - "BearerAuth": { - "type": "http", - "scheme": "bearer" - } - }, - "schemas": { - "HealthObject": { - "type": "object", - "description": "Health object", - "additionalProperties": false, - "required": ["status", "version"], - "properties": { - "status": { - "type": "string", - "description": "Healthy", - "example": "OK" - }, - "version": { - "type": "object", - "description": "The version object", - "example": { - "major": 2, - "minor": 0, - "revision": 0 - }, - "additionalProperties": false, - "required": ["major", "minor", "revision"], - "properties": { - "major": { - "type": "integer", - "minimum": 0 - }, - "minor": { - "type": "integer", - "minimum": 0 - }, - "revision": { - "type": "integer", - "minimum": 0 - } - } - } - } - }, - "TokenObject": { - "type": "object", - "description": "Token object", - "required": ["expires", "token"], - "additionalProperties": false, - "properties": { - "expires": { - "description": "Token Expiry Unix Time", - "example": 1566540249, - "minimum": 1, - "type": "number" - }, - "token": { - "description": "JWT Token", - "example": "eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.ey...xaHKYr3Kk6MvkUjcC4", - "type": "string" - } - } - }, - "ProxyHostObject": { - "type": "object", - "description": "Proxy Host object", - "required": [ - "id", - "created_on", - "modified_on", - "owner_user_id", - "domain_names", - "forward_host", - "forward_port", - "access_list_id", - "certificate_id", - "ssl_forced", - "caching_enabled", - "block_exploits", - "advanced_config", - "meta", - "allow_websocket_upgrade", - "http2_support", - "forward_scheme", - "enabled", - "locations", - "hsts_enabled", - "hsts_subdomains", - "certificate", - "use_default_location", - "ipv6" - ], - "additionalProperties": false, - "properties": { - "id": { - "type": "integer", - "description": "Proxy Host ID", - "minimum": 1, - "example": 1 - }, - "created_on": { - "type": "string", - "description": "Created Date", - "example": "2020-01-30T09:36:08.000Z" - }, - "modified_on": { - "type": "string", - "description": "Modified Date", - "example": "2020-01-30T09:41:04.000Z" - }, - "owner_user_id": { - "type": "integer", - "minimum": 1, - "example": 1 - }, - "domain_names": { - "type": "array", - "minItems": 1, - "items": { - "type": "string", - "minLength": 1 - } - }, - "forward_host": { - "type": "string", - "minLength": 1 - }, - "forward_port": { - "type": "integer", - "minimum": 1 - }, - "access_list_id": { - "type": "integer" - }, - "certificate_id": { - "type": "integer" - }, - "ssl_forced": { - "type": "integer" - }, - "caching_enabled": { - "type": "integer" - }, - "block_exploits": { - "type": "integer" - }, - "advanced_config": { - "type": "string" - }, - "meta": { - "type": "object" - }, - "allow_websocket_upgrade": { - "type": "integer" - }, - "http2_support": { - "type": "integer" - }, - "forward_scheme": { - "type": "string" - }, - "enabled": { - "type": "integer" - }, - "locations": { - "type": "array" - }, - "hsts_enabled": { - "type": "integer" - }, - "hsts_subdomains": { - "type": "integer" - }, - "certificate": { - "type": "object", - "nullable": true - }, - "owner": { - "type": "object", - "nullable": true - }, - "access_list": { - "type": "object", - "nullable": true - }, - "use_default_location": { - "type": "boolean" - }, - "ipv6": { - "type": "boolean" - } - } - }, - "ProxyHostsList": { - "type": "array", - "description": "Proxyn Hosts list", - "items": { - "$ref": "#/components/schemas/ProxyHostObject" - } - }, - "SettingObject": { - "type": "object", - "description": "Setting object", - "required": ["id", "name", "description", "value", "meta"], - "additionalProperties": false, - "properties": { - "id": { - "type": "string", - "description": "Setting ID", - "minLength": 1, - "example": "default-site" - }, - "name": { - "type": "string", - "description": "Setting Display Name", - "minLength": 1, - "example": "Default Site" - }, - "description": { - "type": "string", - "description": "Meaningful description", - "minLength": 1, - "example": "What to show when Nginx is hit with an unknown Host" - }, - "value": { - "description": "Value in almost any form", - "example": "congratulations", - "oneOf": [ - { - "type": "string", - "minLength": 1 - }, - { - "type": "integer" - }, - { - "type": "object" - }, - { - "type": "number" - }, - { - "type": "array" - } - ] - }, - "meta": { - "description": "Extra metadata", - "example": {}, - "type": "object" - } - } - }, - "SettingsList": { - "type": "array", - "description": "Setting list", - "items": { - "$ref": "#/components/schemas/SettingObject" - } - }, - "UserObject": { - "type": "object", - "description": "User object", - "required": ["id", "created_on", "modified_on", "is_disabled", "email", "name", "nickname", "avatar", "roles"], - "additionalProperties": false, - "properties": { - "id": { - "type": "integer", - "description": "User ID", - "minimum": 1, - "example": 1 - }, - "created_on": { - "type": "string", - "description": "Created Date", - "example": "2020-01-30T09:36:08.000Z" - }, - "modified_on": { - "type": "string", - "description": "Modified Date", - "example": "2020-01-30T09:41:04.000Z" - }, - "is_disabled": { - "type": "integer", - "minimum": 0, - "maximum": 1, - "description": "Is user Disabled (0 = false, 1 = true)", - "example": 0 - }, - "email": { - "type": "string", - "description": "Email", - "minLength": 3, - "example": "jc@jc21.com" - }, - "name": { - "type": "string", - "description": "Name", - "minLength": 1, - "example": "Jamie Curnow" - }, - "nickname": { - "type": "string", - "description": "Nickname", - "example": "James" - }, - "avatar": { - "type": "string", - "description": "Gravatar URL based on email, without scheme", - "example": "//www.gravatar.com/avatar/6193176330f8d38747f038c170ddb193?default=mm" - }, - "roles": { - "description": "Roles applied", - "example": ["admin"], - "type": "array", - "items": { - "type": "string" - } - } - } - }, - "UsersList": { - "type": "array", - "description": "User list", - "items": { - "$ref": "#/components/schemas/UserObject" - } - }, - "AuthObject": { - "type": "object", - "description": "Authentication Object", - "required": ["type", "secret"], - "properties": { - "type": { - "type": "string", - "pattern": "^password$", - "example": "password" - }, - "current": { - "type": "string", - "minLength": 1, - "maxLength": 64, - "example": "changeme" - }, - "secret": { - "type": "string", - "minLength": 8, - "maxLength": 64, - "example": "mySuperN3wP@ssword!" - } - } - }, - "PermissionsObject": { - "type": "object", - "properties": { - "visibility": { - "type": "string", - "description": "Visibility Type", - "enum": ["all", "user"] - }, - "access_lists": { - "type": "string", - "description": "Access Lists Permissions", - "enum": ["hidden", "view", "manage"] - }, - "dead_hosts": { - "type": "string", - "description": "404 Hosts Permissions", - "enum": ["hidden", "view", "manage"] - }, - "proxy_hosts": { - "type": "string", - "description": "Proxy Hosts Permissions", - "enum": ["hidden", "view", "manage"] - }, - "redirection_hosts": { - "type": "string", - "description": "Redirection Permissions", - "enum": ["hidden", "view", "manage"] - }, - "streams": { - "type": "string", - "description": "Streams Permissions", - "enum": ["hidden", "view", "manage"] - }, - "certificates": { - "type": "string", - "description": "Certificates Permissions", - "enum": ["hidden", "view", "manage"] - } - } - }, - "HostReportObject": { - "type": "object", - "properties": { - "proxy": { - "type": "integer", - "description": "Proxy Hosts Count" - }, - "redirection": { - "type": "integer", - "description": "Redirection Hosts Count" - }, - "stream": { - "type": "integer", - "description": "Streams Count" - }, - "dead": { - "type": "integer", - "description": "404 Hosts Count" - } - } - } - } - } -} diff --git a/backend/internal/proxy-host.js b/backend/internal/proxy-host.js index 0ea168789..61ac8b8c7 100644 --- a/backend/internal/proxy-host.js +++ b/backend/internal/proxy-host.js @@ -8,7 +8,7 @@ const internalAuditLog = require('./audit-log'); const internalCertificate = require('./certificate'); function omissions () { - return ['is_deleted']; + return ['is_deleted', 'owner.is_deleted']; } const internalProxyHost = { diff --git a/backend/lib/access.js b/backend/lib/access.js index 5b9ebc93c..57dd379c8 100644 --- a/backend/lib/access.js +++ b/backend/lib/access.js @@ -10,7 +10,7 @@ const _ = require('lodash'); const logger = require('../logger').access; -const validator = require('ajv'); +const Ajv = require('ajv/dist/2020'); const error = require('./error'); const userModel = require('../models/user'); const proxyHostModel = require('../models/proxy_host'); @@ -174,7 +174,6 @@ module.exports = function (token_string) { let schema = { $id: 'objects', - $schema: 'http://json-schema.org/draft-07/schema#', description: 'Actor Properties', type: 'object', additionalProperties: false, @@ -251,7 +250,7 @@ module.exports = function (token_string) { // Initialised, token decoded ok return this.getObjectSchema(permission) .then((objectSchema) => { - let data_schema = { + const data_schema = { [permission]: { data: data, scope: Token.get('scope'), @@ -267,7 +266,6 @@ module.exports = function (token_string) { }; let permissionSchema = { - $schema: 'http://json-schema.org/draft-07/schema#', $async: true, $id: 'permissions', additionalProperties: false, @@ -276,14 +274,9 @@ module.exports = function (token_string) { permissionSchema.properties[permission] = require('./access/' + permission.replace(/:/gim, '-') + '.json'); - // logger.info('objectSchema', JSON.stringify(objectSchema, null, 2)); - // logger.info('permissionSchema', JSON.stringify(permissionSchema, null, 2)); - // logger.info('data_schema', JSON.stringify(data_schema, null, 2)); - - let ajv = validator({ + const ajv = new Ajv({ verbose: true, allErrors: true, - format: 'full', missingRefs: 'fail', breakOnError: true, coerceTypes: true, diff --git a/backend/lib/access/permissions.json b/backend/lib/access/permissions.json index 8480f9a1c..e7a82ece3 100644 --- a/backend/lib/access/permissions.json +++ b/backend/lib/access/permissions.json @@ -1,5 +1,4 @@ { - "$schema": "http://json-schema.org/draft-07/schema#", "$id": "perms", "definitions": { "view": { diff --git a/backend/lib/access/roles.json b/backend/lib/access/roles.json index 16b33b55b..c97313da8 100644 --- a/backend/lib/access/roles.json +++ b/backend/lib/access/roles.json @@ -1,5 +1,4 @@ { - "$schema": "http://json-schema.org/draft-07/schema#", "$id": "roles", "definitions": { "admin": { diff --git a/backend/lib/helpers.js b/backend/lib/helpers.js index e38be991e..f7e98bebc 100644 --- a/backend/lib/helpers.js +++ b/backend/lib/helpers.js @@ -27,6 +27,24 @@ module.exports = { } return null; + }, + + convertIntFieldsToBool: function (obj, fields) { + fields.forEach(function (field) { + if (typeof obj[field] !== 'undefined') { + obj[field] = obj[field] === 1; + } + }); + return obj; + }, + + convertBoolFieldsToInt: function (obj, fields) { + fields.forEach(function (field) { + if (typeof obj[field] !== 'undefined') { + obj[field] = obj[field] ? 1 : 0; + } + }); + return obj; } }; diff --git a/backend/lib/validator/api.js b/backend/lib/validator/api.js index c0876ab32..fb31e64c6 100644 --- a/backend/lib/validator/api.js +++ b/backend/lib/validator/api.js @@ -1,11 +1,12 @@ +const Ajv = require('ajv/dist/2020'); const error = require('../error'); -const ajv = require('ajv')({ - verbose: true, - validateSchema: true, - allErrors: false, - format: 'full', - coerceTypes: true +const ajv = new Ajv({ + verbose: true, + allErrors: true, + allowUnionTypes: true, + strict: false, + coerceTypes: true, }); /** @@ -25,8 +26,8 @@ function apiValidator (schema, payload/*, description*/) { return; } - let validate = ajv.compile(schema); - let valid = validate(payload); + const validate = ajv.compile(schema); + const valid = validate(payload); if (valid && !validate.errors) { resolve(payload); diff --git a/backend/lib/validator/index.js b/backend/lib/validator/index.js index 3c5265b17..c6d240967 100644 --- a/backend/lib/validator/index.js +++ b/backend/lib/validator/index.js @@ -1,15 +1,17 @@ const _ = require('lodash'); +const Ajv = require('ajv/dist/2020'); const error = require('../error'); const commonDefinitions = require('../../schema/common.json'); RegExp.prototype.toJSON = RegExp.prototype.toString; -const ajv = require('ajv')({ - verbose: true, - allErrors: true, - format: 'full', // strict regexes for format checks - coerceTypes: true, - schemas: [commonDefinitions] +const ajv = new Ajv({ + verbose: true, + allErrors: true, + allowUnionTypes: true, + coerceTypes: true, + strict: false, + schemas: [commonDefinitions] }); /** @@ -38,7 +40,6 @@ function validator (schema, payload) { } } }); - } module.exports = validator; diff --git a/backend/models/access_list.js b/backend/models/access_list.js index fbf9bda77..959df05f3 100644 --- a/backend/models/access_list.js +++ b/backend/models/access_list.js @@ -2,6 +2,7 @@ // http://vincit.github.io/objection.js/ const db = require('../db'); +const helpers = require('../lib/helpers'); const Model = require('objection').Model; const User = require('./user'); const AccessListAuth = require('./access_list_auth'); @@ -10,6 +11,12 @@ const now = require('./now_helper'); Model.knex(db); +const boolFields = [ + 'is_deleted', + 'satisfy_any', + 'pass_auth', +]; + class AccessList extends Model { $beforeInsert () { this.created_on = now(); @@ -25,6 +32,16 @@ class AccessList extends Model { this.modified_on = now(); } + $parseDatabaseJson(json) { + json = super.$parseDatabaseJson(json); + return helpers.convertIntFieldsToBool(json, boolFields); + } + + $formatDatabaseJson(json) { + json = helpers.convertBoolFieldsToInt(json, boolFields); + return super.$formatDatabaseJson(json); + } + static get name () { return 'AccessList'; } diff --git a/backend/models/auth.js b/backend/models/auth.js index 2ee431975..469e96bf4 100644 --- a/backend/models/auth.js +++ b/backend/models/auth.js @@ -1,14 +1,19 @@ // Objection Docs: // http://vincit.github.io/objection.js/ -const bcrypt = require('bcrypt'); -const db = require('../db'); -const Model = require('objection').Model; -const User = require('./user'); -const now = require('./now_helper'); +const bcrypt = require('bcrypt'); +const db = require('../db'); +const helpers = require('../lib/helpers'); +const Model = require('objection').Model; +const User = require('./user'); +const now = require('./now_helper'); Model.knex(db); +const boolFields = [ + 'is_deleted', +]; + function encryptPassword () { /* jshint -W040 */ let _this = this; @@ -41,6 +46,16 @@ class Auth extends Model { return encryptPassword.apply(this, queryContext); } + $parseDatabaseJson(json) { + json = super.$parseDatabaseJson(json); + return helpers.convertIntFieldsToBool(json, boolFields); + } + + $formatDatabaseJson(json) { + json = helpers.convertBoolFieldsToInt(json, boolFields); + return super.$formatDatabaseJson(json); + } + /** * Verify a plain password against the encrypted password * diff --git a/backend/models/certificate.js b/backend/models/certificate.js index 4f0f2ef64..534d927cb 100644 --- a/backend/models/certificate.js +++ b/backend/models/certificate.js @@ -1,13 +1,18 @@ // Objection Docs: // http://vincit.github.io/objection.js/ -const db = require('../db'); -const Model = require('objection').Model; -const User = require('./user'); -const now = require('./now_helper'); +const db = require('../db'); +const helpers = require('../lib/helpers'); +const Model = require('objection').Model; +const User = require('./user'); +const now = require('./now_helper'); Model.knex(db); +const boolFields = [ + 'is_deleted', +]; + class Certificate extends Model { $beforeInsert () { this.created_on = now(); @@ -40,6 +45,16 @@ class Certificate extends Model { } } + $parseDatabaseJson(json) { + json = super.$parseDatabaseJson(json); + return helpers.convertIntFieldsToBool(json, boolFields); + } + + $formatDatabaseJson(json) { + json = helpers.convertBoolFieldsToInt(json, boolFields); + return super.$formatDatabaseJson(json); + } + static get name () { return 'Certificate'; } diff --git a/backend/models/dead_host.js b/backend/models/dead_host.js index 2e31043ae..483da3b6b 100644 --- a/backend/models/dead_host.js +++ b/backend/models/dead_host.js @@ -2,6 +2,7 @@ // http://vincit.github.io/objection.js/ const db = require('../db'); +const helpers = require('../lib/helpers'); const Model = require('objection').Model; const User = require('./user'); const Certificate = require('./certificate'); @@ -9,6 +10,11 @@ const now = require('./now_helper'); Model.knex(db); +const boolFields = [ + 'is_deleted', + 'enabled', +]; + class DeadHost extends Model { $beforeInsert () { this.created_on = now(); @@ -36,6 +42,16 @@ class DeadHost extends Model { } } + $parseDatabaseJson(json) { + json = super.$parseDatabaseJson(json); + return helpers.convertIntFieldsToBool(json, boolFields); + } + + $formatDatabaseJson(json) { + json = helpers.convertBoolFieldsToInt(json, boolFields); + return super.$formatDatabaseJson(json); + } + static get name () { return 'DeadHost'; } diff --git a/backend/models/proxy_host.js b/backend/models/proxy_host.js index d84181cf1..07aa5dd3c 100644 --- a/backend/models/proxy_host.js +++ b/backend/models/proxy_host.js @@ -2,6 +2,7 @@ // http://vincit.github.io/objection.js/ const db = require('../db'); +const helpers = require('../lib/helpers'); const Model = require('objection').Model; const User = require('./user'); const AccessList = require('./access_list'); @@ -10,6 +11,18 @@ const now = require('./now_helper'); Model.knex(db); +const boolFields = [ + 'is_deleted', + 'ssl_forced', + 'caching_enabled', + 'block_exploits', + 'allow_websocket_upgrade', + 'http2_support', + 'enabled', + 'hsts_enabled', + 'hsts_subdomains', +]; + class ProxyHost extends Model { $beforeInsert () { this.created_on = now(); @@ -37,6 +50,16 @@ class ProxyHost extends Model { } } + $parseDatabaseJson(json) { + json = super.$parseDatabaseJson(json); + return helpers.convertIntFieldsToBool(json, boolFields); + } + + $formatDatabaseJson(json) { + json = helpers.convertBoolFieldsToInt(json, boolFields); + return super.$formatDatabaseJson(json); + } + static get name () { return 'ProxyHost'; } diff --git a/backend/models/redirection_host.js b/backend/models/redirection_host.js index c90a6de6c..556742f0c 100644 --- a/backend/models/redirection_host.js +++ b/backend/models/redirection_host.js @@ -3,6 +3,7 @@ // http://vincit.github.io/objection.js/ const db = require('../db'); +const helpers = require('../lib/helpers'); const Model = require('objection').Model; const User = require('./user'); const Certificate = require('./certificate'); @@ -10,6 +11,14 @@ const now = require('./now_helper'); Model.knex(db); +const boolFields = [ + 'is_deleted', + 'enabled', + 'preserve_path', + 'ssl_forced', + 'block_exploits', +]; + class RedirectionHost extends Model { $beforeInsert () { this.created_on = now(); @@ -37,6 +46,16 @@ class RedirectionHost extends Model { } } + $parseDatabaseJson(json) { + json = super.$parseDatabaseJson(json); + return helpers.convertIntFieldsToBool(json, boolFields); + } + + $formatDatabaseJson(json) { + json = helpers.convertBoolFieldsToInt(json, boolFields); + return super.$formatDatabaseJson(json); + } + static get name () { return 'RedirectionHost'; } diff --git a/backend/models/stream.js b/backend/models/stream.js index 7d84d2c36..b96ca5a17 100644 --- a/backend/models/stream.js +++ b/backend/models/stream.js @@ -1,13 +1,20 @@ // Objection Docs: // http://vincit.github.io/objection.js/ -const db = require('../db'); -const Model = require('objection').Model; -const User = require('./user'); -const now = require('./now_helper'); +const db = require('../db'); +const helpers = require('../lib/helpers'); +const Model = require('objection').Model; +const User = require('./user'); +const now = require('./now_helper'); Model.knex(db); +const boolFields = [ + 'is_deleted', + 'tcp_forwarding', + 'udp_forwarding', +]; + class Stream extends Model { $beforeInsert () { this.created_on = now(); @@ -23,6 +30,16 @@ class Stream extends Model { this.modified_on = now(); } + $parseDatabaseJson(json) { + json = super.$parseDatabaseJson(json); + return helpers.convertIntFieldsToBool(json, boolFields); + } + + $formatDatabaseJson(json) { + json = helpers.convertBoolFieldsToInt(json, boolFields); + return super.$formatDatabaseJson(json); + } + static get name () { return 'Stream'; } diff --git a/backend/models/user.js b/backend/models/user.js index 93489fefe..78fd3dd67 100644 --- a/backend/models/user.js +++ b/backend/models/user.js @@ -2,12 +2,18 @@ // http://vincit.github.io/objection.js/ const db = require('../db'); +const helpers = require('../lib/helpers'); const Model = require('objection').Model; const UserPermission = require('./user_permission'); const now = require('./now_helper'); Model.knex(db); +const boolFields = [ + 'is_deleted', + 'is_disabled', +]; + class User extends Model { $beforeInsert () { this.created_on = now(); @@ -23,6 +29,16 @@ class User extends Model { this.modified_on = now(); } + $parseDatabaseJson(json) { + json = super.$parseDatabaseJson(json); + return helpers.convertIntFieldsToBool(json, boolFields); + } + + $formatDatabaseJson(json) { + json = helpers.convertBoolFieldsToInt(json, boolFields); + return super.$formatDatabaseJson(json); + } + static get name () { return 'User'; } diff --git a/backend/package.json b/backend/package.json index 379c6e68c..c55df861e 100644 --- a/backend/package.json +++ b/backend/package.json @@ -2,10 +2,10 @@ "name": "nginx-proxy-manager", "version": "0.0.0", "description": "A beautiful interface for creating Nginx endpoints", - "main": "js/index.js", + "main": "index.js", "dependencies": { "@apidevtools/json-schema-ref-parser": "^11.7.0", - "ajv": "^6.12.0", + "ajv": "^8.17.1", "archiver": "^5.3.0", "batchflow": "^0.4.0", "bcrypt": "^5.0.0", @@ -14,7 +14,6 @@ "express": "^4.19.2", "express-fileupload": "^1.1.9", "gravatar": "^1.8.0", - "json-schema-ref-parser": "^8.0.0", "jsonwebtoken": "^9.0.0", "knex": "2.4.2", "liquidjs": "10.6.1", @@ -35,9 +34,14 @@ "author": "Jamie Curnow ", "license": "MIT", "devDependencies": { + "@apidevtools/swagger-parser": "^10.1.0", + "chalk": "4.1.2", "eslint": "^8.36.0", "eslint-plugin-align-assignments": "^1.1.2", "nodemon": "^2.0.2", "prettier": "^2.0.4" + }, + "scripts": { + "validate-schema": "node validate-schema.js" } } diff --git a/backend/routes/audit-log.js b/backend/routes/audit-log.js index 6467a63d2..c68c7b35b 100644 --- a/backend/routes/audit-log.js +++ b/backend/routes/audit-log.js @@ -29,10 +29,10 @@ router additionalProperties: false, properties: { expand: { - $ref: 'common#/definitions/expand' + $ref: 'common#/properties/expand' }, query: { - $ref: 'common#/definitions/query' + $ref: 'common#/properties/query' } } }, { diff --git a/backend/routes/nginx/access_lists.js b/backend/routes/nginx/access_lists.js index 79e920ddb..383751277 100644 --- a/backend/routes/nginx/access_lists.js +++ b/backend/routes/nginx/access_lists.js @@ -31,10 +31,10 @@ router additionalProperties: false, properties: { expand: { - $ref: 'common#/definitions/expand' + $ref: 'common#/properties/expand' }, query: { - $ref: 'common#/definitions/query' + $ref: 'common#/properties/query' } } }, { @@ -91,10 +91,10 @@ router additionalProperties: false, properties: { list_id: { - $ref: 'common#/definitions/id' + $ref: 'common#/properties/id' }, expand: { - $ref: 'common#/definitions/expand' + $ref: 'common#/properties/expand' } } }, { diff --git a/backend/routes/nginx/certificates.js b/backend/routes/nginx/certificates.js index b6ad7c69c..bf47c03fc 100644 --- a/backend/routes/nginx/certificates.js +++ b/backend/routes/nginx/certificates.js @@ -32,10 +32,10 @@ router additionalProperties: false, properties: { expand: { - $ref: 'common#/definitions/expand' + $ref: 'common#/properties/expand' }, query: { - $ref: 'common#/definitions/query' + $ref: 'common#/properties/query' } } }, { @@ -124,10 +124,10 @@ router additionalProperties: false, properties: { certificate_id: { - $ref: 'common#/definitions/id' + $ref: 'common#/properties/id' }, expand: { - $ref: 'common#/definitions/expand' + $ref: 'common#/properties/expand' } } }, { diff --git a/backend/routes/nginx/dead_hosts.js b/backend/routes/nginx/dead_hosts.js index 4523d3e42..83b377653 100644 --- a/backend/routes/nginx/dead_hosts.js +++ b/backend/routes/nginx/dead_hosts.js @@ -31,10 +31,10 @@ router additionalProperties: false, properties: { expand: { - $ref: 'common#/definitions/expand' + $ref: 'common#/properties/expand' }, query: { - $ref: 'common#/definitions/query' + $ref: 'common#/properties/query' } } }, { @@ -91,10 +91,10 @@ router additionalProperties: false, properties: { host_id: { - $ref: 'common#/definitions/id' + $ref: 'common#/properties/id' }, expand: { - $ref: 'common#/definitions/expand' + $ref: 'common#/properties/expand' } } }, { diff --git a/backend/routes/nginx/proxy_hosts.js b/backend/routes/nginx/proxy_hosts.js index 6ace41954..3be4582a8 100644 --- a/backend/routes/nginx/proxy_hosts.js +++ b/backend/routes/nginx/proxy_hosts.js @@ -31,10 +31,10 @@ router additionalProperties: false, properties: { expand: { - $ref: 'common#/definitions/expand' + $ref: 'common#/properties/expand' }, query: { - $ref: 'common#/definitions/query' + $ref: 'common#/properties/query' } } }, { @@ -91,10 +91,10 @@ router additionalProperties: false, properties: { host_id: { - $ref: 'common#/definitions/id' + $ref: 'common#/properties/id' }, expand: { - $ref: 'common#/definitions/expand' + $ref: 'common#/properties/expand' } } }, { diff --git a/backend/routes/nginx/redirection_hosts.js b/backend/routes/nginx/redirection_hosts.js index de334e74e..a46feb841 100644 --- a/backend/routes/nginx/redirection_hosts.js +++ b/backend/routes/nginx/redirection_hosts.js @@ -31,10 +31,10 @@ router additionalProperties: false, properties: { expand: { - $ref: 'common#/definitions/expand' + $ref: 'common#/properties/expand' }, query: { - $ref: 'common#/definitions/query' + $ref: 'common#/properties/query' } } }, { @@ -91,10 +91,10 @@ router additionalProperties: false, properties: { host_id: { - $ref: 'common#/definitions/id' + $ref: 'common#/properties/id' }, expand: { - $ref: 'common#/definitions/expand' + $ref: 'common#/properties/expand' } } }, { diff --git a/backend/routes/nginx/streams.js b/backend/routes/nginx/streams.js index 1f68c1989..c033f2ef1 100644 --- a/backend/routes/nginx/streams.js +++ b/backend/routes/nginx/streams.js @@ -31,10 +31,10 @@ router additionalProperties: false, properties: { expand: { - $ref: 'common#/definitions/expand' + $ref: 'common#/properties/expand' }, query: { - $ref: 'common#/definitions/query' + $ref: 'common#/properties/query' } } }, { @@ -91,10 +91,10 @@ router additionalProperties: false, properties: { stream_id: { - $ref: 'common#/definitions/id' + $ref: 'common#/properties/id' }, expand: { - $ref: 'common#/definitions/expand' + $ref: 'common#/properties/expand' } } }, { diff --git a/backend/routes/users.js b/backend/routes/users.js index 475156675..f8ce366c9 100644 --- a/backend/routes/users.js +++ b/backend/routes/users.js @@ -32,10 +32,10 @@ router additionalProperties: false, properties: { expand: { - $ref: 'common#/definitions/expand' + $ref: 'common#/properties/expand' }, query: { - $ref: 'common#/definitions/query' + $ref: 'common#/properties/query' } } }, { @@ -97,10 +97,10 @@ router additionalProperties: false, properties: { user_id: { - $ref: 'common#/definitions/id' + $ref: 'common#/properties/id' }, expand: { - $ref: 'common#/definitions/expand' + $ref: 'common#/properties/expand' } } }, { diff --git a/backend/schema/common.json b/backend/schema/common.json index dd8247a4b..ebeb34416 100644 --- a/backend/schema/common.json +++ b/backend/schema/common.json @@ -1,10 +1,10 @@ { - "$schema": "http://json-schema.org/draft-07/schema#", + "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "common", - "definitions": { + "type": "object", + "properties": { "id": { "description": "Unique identifier", - "example": 123456, "readOnly": true, "type": "integer", "minimum": 1 @@ -37,25 +37,21 @@ }, "created_on": { "description": "Date and time of creation", - "format": "date-time", "readOnly": true, "type": "string" }, "modified_on": { "description": "Date and time of last update", - "format": "date-time", "readOnly": true, "type": "string" }, "user_id": { "description": "User ID", - "example": 1234, "type": "integer", "minimum": 1 }, "certificate_id": { "description": "Certificate ID", - "example": 1234, "anyOf": [ { "type": "integer", @@ -69,13 +65,11 @@ }, "access_list_id": { "description": "Access List ID", - "example": 1234, "type": "integer", "minimum": 0 }, "domain_names": { "description": "Domain Names separated by a comma", - "example": "*.jc21.com,blog.jc21.com", "type": "array", "minItems": 1, "maxItems": 100, @@ -87,22 +81,18 @@ }, "enabled": { "description": "Is Enabled", - "example": true, "type": "boolean" }, "ssl_forced": { "description": "Is SSL Forced", - "example": false, "type": "boolean" }, "hsts_enabled": { "description": "Is HSTS Enabled", - "example": false, "type": "boolean" }, "hsts_subdomains": { "description": "Is HSTS applicable to all subdomains", - "example": false, "type": "boolean" }, "ssl_provider": { @@ -111,17 +101,14 @@ }, "http2_support": { "description": "HTTP2 Protocol Support", - "example": false, "type": "boolean" }, "block_exploits": { "description": "Should we block common exploits", - "example": true, "type": "boolean" }, "caching_enabled": { "description": "Should we cache assets", - "example": true, "type": "boolean" } } diff --git a/backend/schema/components/access-list-object.json b/backend/schema/components/access-list-object.json index c6ed51a58..cd0218d72 100644 --- a/backend/schema/components/access-list-object.json +++ b/backend/schema/components/access-list-object.json @@ -5,16 +5,16 @@ "additionalProperties": false, "properties": { "id": { - "$ref": "../common.json#/definitions/id" + "$ref": "../common.json#/properties/id" }, "created_on": { - "$ref": "../common.json#/definitions/created_on" + "$ref": "../common.json#/properties/created_on" }, "modified_on": { - "$ref": "../common.json#/definitions/modified_on" + "$ref": "../common.json#/properties/modified_on" }, "owner_user_id": { - "$ref": "../common.json#/definitions/user_id" + "$ref": "../common.json#/properties/user_id" }, "name": { "type": "string", diff --git a/backend/schema/components/audit-log-object.json b/backend/schema/components/audit-log-object.json index f38606e12..3e5e8594b 100644 --- a/backend/schema/components/audit-log-object.json +++ b/backend/schema/components/audit-log-object.json @@ -5,22 +5,22 @@ "additionalProperties": false, "properties": { "id": { - "$ref": "../common.json#/definitions/id" + "$ref": "../common.json#/properties/id" }, "created_on": { - "$ref": "../common.json#/definitions/created_on" + "$ref": "../common.json#/properties/created_on" }, "modified_on": { - "$ref": "../common.json#/definitions/modified_on" + "$ref": "../common.json#/properties/modified_on" }, "user_id": { - "$ref": "../common.json#/definitions/user_id" + "$ref": "../common.json#/properties/user_id" }, "object_type": { "type": "string" }, "object_id": { - "$ref": "../common.json#/definitions/id" + "$ref": "../common.json#/properties/id" }, "action": { "type": "string" diff --git a/backend/schema/components/certificate-object.json b/backend/schema/components/certificate-object.json index 8e6a28523..04cd89801 100644 --- a/backend/schema/components/certificate-object.json +++ b/backend/schema/components/certificate-object.json @@ -5,30 +5,29 @@ "additionalProperties": false, "properties": { "id": { - "$ref": "../common.json#/definitions/id" + "$ref": "../common.json#/properties/id" }, "created_on": { - "$ref": "../common.json#/definitions/created_on" + "$ref": "../common.json#/properties/created_on" }, "modified_on": { - "$ref": "../common.json#/definitions/modified_on" + "$ref": "../common.json#/properties/modified_on" }, "owner_user_id": { - "$ref": "../common.json#/definitions/user_id" + "$ref": "../common.json#/properties/user_id" }, "provider": { - "$ref": "../common.json#/definitions/ssl_provider" + "$ref": "../common.json#/properties/ssl_provider" }, "nice_name": { "type": "string", "description": "Nice Name for the custom certificate" }, "domain_names": { - "$ref": "../common.json#/definitions/domain_names" + "$ref": "../common.json#/properties/domain_names" }, "expires_on": { "description": "Date and time of expiration", - "format": "date-time", "readOnly": true, "type": "string" }, @@ -37,8 +36,7 @@ "additionalProperties": false, "properties": { "letsencrypt_email": { - "type": "string", - "format": "email" + "type": "string" }, "letsencrypt_agree": { "type": "boolean" diff --git a/backend/schema/components/dead-host-object.json b/backend/schema/components/dead-host-object.json index 84ad17793..792c2f81e 100644 --- a/backend/schema/components/dead-host-object.json +++ b/backend/schema/components/dead-host-object.json @@ -5,40 +5,40 @@ "additionalProperties": false, "properties": { "id": { - "$ref": "../common.json#/definitions/id" + "$ref": "../common.json#/properties/id" }, "created_on": { - "$ref": "../common.json#/definitions/created_on" + "$ref": "../common.json#/properties/created_on" }, "modified_on": { - "$ref": "../common.json#/definitions/modified_on" + "$ref": "../common.json#/properties/modified_on" }, "owner_user_id": { - "$ref": "../common.json#/definitions/user_id" + "$ref": "../common.json#/properties/user_id" }, "domain_names": { - "$ref": "../common.json#/definitions/domain_names" + "$ref": "../common.json#/properties/domain_names" }, "certificate_id": { - "$ref": "../common.json#/definitions/certificate_id" + "$ref": "../common.json#/properties/certificate_id" }, "ssl_forced": { - "$ref": "../common.json#/definitions/ssl_forced" + "$ref": "../common.json#/properties/ssl_forced" }, "hsts_enabled": { - "$ref": "../common.json#/definitions/hsts_enabled" + "$ref": "../common.json#/properties/hsts_enabled" }, "hsts_subdomains": { - "$ref": "../common.json#/definitions/hsts_subdomains" + "$ref": "../common.json#/properties/hsts_subdomains" }, "http2_support": { - "$ref": "../common.json#/definitions/http2_support" + "$ref": "../common.json#/properties/http2_support" }, "advanced_config": { "type": "string" }, "enabled": { - "$ref": "../common.json#/definitions/enabled" + "$ref": "../common.json#/properties/enabled" }, "meta": { "type": "object" diff --git a/backend/schema/components/proxy-host-object.json b/backend/schema/components/proxy-host-object.json index 18414bd4c..a64a58c8f 100644 --- a/backend/schema/components/proxy-host-object.json +++ b/backend/schema/components/proxy-host-object.json @@ -30,19 +30,19 @@ "additionalProperties": false, "properties": { "id": { - "$ref": "../common.json#/definitions/id" + "$ref": "../common.json#/properties/id" }, "created_on": { - "$ref": "../common.json#/definitions/created_on" + "$ref": "../common.json#/properties/created_on" }, "modified_on": { - "$ref": "../common.json#/definitions/modified_on" + "$ref": "../common.json#/properties/modified_on" }, "owner_user_id": { - "$ref": "../common.json#/definitions/user_id" + "$ref": "../common.json#/properties/user_id" }, "domain_names": { - "$ref": "../common.json#/definitions/domain_names" + "$ref": "../common.json#/properties/domain_names" }, "forward_host": { "type": "string", @@ -55,19 +55,19 @@ "maximum": 65535 }, "access_list_id": { - "$ref": "../common.json#/definitions/access_list_id" + "$ref": "../common.json#/properties/access_list_id" }, "certificate_id": { - "$ref": "../common.json#/definitions/certificate_id" + "$ref": "../common.json#/properties/certificate_id" }, "ssl_forced": { - "$ref": "../common.json#/definitions/ssl_forced" + "$ref": "../common.json#/properties/ssl_forced" }, "caching_enabled": { - "$ref": "../common.json#/definitions/caching_enabled" + "$ref": "../common.json#/properties/caching_enabled" }, "block_exploits": { - "$ref": "../common.json#/definitions/block_exploits" + "$ref": "../common.json#/properties/block_exploits" }, "advanced_config": { "type": "string" @@ -81,14 +81,14 @@ "type": "boolean" }, "http2_support": { - "$ref": "../common.json#/definitions/http2_support" + "$ref": "../common.json#/properties/http2_support" }, "forward_scheme": { "type": "string", "enum": ["http", "https"] }, "enabled": { - "$ref": "../common.json#/definitions/enabled" + "$ref": "../common.json#/properties/enabled" }, "locations": { "type": "array", @@ -124,19 +124,33 @@ } }, "hsts_enabled": { - "$ref": "../common.json#/definitions/hsts_enabled" + "$ref": "../common.json#/properties/hsts_enabled" }, "hsts_subdomains": { - "$ref": "../common.json#/definitions/hsts_subdomains" + "$ref": "../common.json#/properties/hsts_subdomains" }, "certificate": { - "$ref": "./certificate-object.json" + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "./certificate-object.json" + } + ] }, "owner": { "$ref": "./user-object.json" }, "access_list": { - "$ref": "./access-list-object.json" + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "./access-list-object.json" + } + ] }, "use_default_location": { "type": "boolean" diff --git a/backend/schema/components/redirection-host-object.json b/backend/schema/components/redirection-host-object.json index 080b75e59..cc4dbdd2f 100644 --- a/backend/schema/components/redirection-host-object.json +++ b/backend/schema/components/redirection-host-object.json @@ -5,19 +5,19 @@ "additionalProperties": false, "properties": { "id": { - "$ref": "../common.json#/definitions/id" + "$ref": "../common.json#/properties/id" }, "created_on": { - "$ref": "../common.json#/definitions/created_on" + "$ref": "../common.json#/properties/created_on" }, "modified_on": { - "$ref": "../common.json#/definitions/modified_on" + "$ref": "../common.json#/properties/modified_on" }, "owner_user_id": { - "$ref": "../common.json#/definitions/user_id" + "$ref": "../common.json#/properties/user_id" }, "domain_names": { - "$ref": "../common.json#/definitions/domain_names" + "$ref": "../common.json#/properties/domain_names" }, "forward_http_code": { "description": "Redirect HTTP Status Code", @@ -42,28 +42,28 @@ "type": "boolean" }, "certificate_id": { - "$ref": "../common.json#/definitions/certificate_id" + "$ref": "../common.json#/properties/certificate_id" }, "ssl_forced": { - "$ref": "../common.json#/definitions/ssl_forced" + "$ref": "../common.json#/properties/ssl_forced" }, "hsts_enabled": { - "$ref": "../common.json#/definitions/hsts_enabled" + "$ref": "../common.json#/properties/hsts_enabled" }, "hsts_subdomains": { - "$ref": "../common.json#/definitions/hsts_subdomains" + "$ref": "../common.json#/properties/hsts_subdomains" }, "http2_support": { - "$ref": "../common.json#/definitions/http2_support" + "$ref": "../common.json#/properties/http2_support" }, "block_exploits": { - "$ref": "../common.json#/definitions/block_exploits" + "$ref": "../common.json#/properties/block_exploits" }, "advanced_config": { "type": "string" }, "enabled": { - "$ref": "../common.json#/definitions/enabled" + "$ref": "../common.json#/properties/enabled" }, "meta": { "type": "object" diff --git a/backend/schema/components/stream-object.json b/backend/schema/components/stream-object.json index 9b92d26dd..516c7f891 100644 --- a/backend/schema/components/stream-object.json +++ b/backend/schema/components/stream-object.json @@ -5,16 +5,16 @@ "additionalProperties": false, "properties": { "id": { - "$ref": "../common.json#/definitions/id" + "$ref": "../common.json#/properties/id" }, "created_on": { - "$ref": "../common.json#/definitions/created_on" + "$ref": "../common.json#/properties/created_on" }, "modified_on": { - "$ref": "../common.json#/definitions/modified_on" + "$ref": "../common.json#/properties/modified_on" }, "owner_user_id": { - "$ref": "../common.json#/definitions/user_id" + "$ref": "../common.json#/properties/user_id" }, "incoming_port": { "type": "integer", @@ -51,7 +51,7 @@ "type": "boolean" }, "enabled": { - "$ref": "../common.json#/definitions/enabled" + "$ref": "../common.json#/properties/enabled" }, "meta": { "type": "object" diff --git a/backend/schema/components/user-object.json b/backend/schema/components/user-object.json index 7f01a6ac8..180e8f197 100644 --- a/backend/schema/components/user-object.json +++ b/backend/schema/components/user-object.json @@ -21,11 +21,9 @@ "example": "2020-01-30T09:41:04.000Z" }, "is_disabled": { - "type": "integer", - "minimum": 0, - "maximum": 1, - "description": "Is user Disabled (0 = false, 1 = true)", - "example": 0 + "type": "boolean", + "description": "Is user Disabled", + "example": true }, "email": { "type": "string", diff --git a/backend/schema/paths/nginx/access-lists/get.json b/backend/schema/paths/nginx/access-lists/get.json index 7774b906a..a8b9adc69 100644 --- a/backend/schema/paths/nginx/access-lists/get.json +++ b/backend/schema/paths/nginx/access-lists/get.json @@ -33,8 +33,8 @@ "owner_user_id": 1, "name": "test1234", "meta": {}, - "satisfy_any": 1, - "pass_auth": 0, + "satisfy_any": true, + "pass_auth": false, "proxy_host_count": 0 } ] diff --git a/backend/schema/paths/nginx/access-lists/listID/get.json b/backend/schema/paths/nginx/access-lists/listID/get.json index 011ad77e6..e67023f89 100644 --- a/backend/schema/paths/nginx/access-lists/listID/get.json +++ b/backend/schema/paths/nginx/access-lists/listID/get.json @@ -30,7 +30,7 @@ "id": 1, "created_on": "2020-01-30T09:36:08.000Z", "modified_on": "2020-01-30T09:41:04.000Z", - "is_disabled": 0, + "is_disabled": false, "email": "jc@jc21.com", "name": "Jamie Curnow", "nickname": "James", diff --git a/backend/schema/paths/nginx/access-lists/listID/put.json b/backend/schema/paths/nginx/access-lists/listID/put.json index 95ecaa619..3a69f8567 100644 --- a/backend/schema/paths/nginx/access-lists/listID/put.json +++ b/backend/schema/paths/nginx/access-lists/listID/put.json @@ -102,15 +102,15 @@ "owner_user_id": 1, "name": "test123!!", "meta": {}, - "satisfy_any": 1, - "pass_auth": 0, + "satisfy_any": true, + "pass_auth": false, "proxy_host_count": 0, "owner": { "id": 1, "created_on": "2024-10-07T22:43:55.000Z", "modified_on": "2024-10-08T12:52:54.000Z", - "is_deleted": 0, - "is_disabled": 0, + "is_deleted": false, + "is_disabled": false, "email": "admin@example.com", "name": "Administrator", "nickname": "some guy", diff --git a/backend/schema/paths/nginx/access-lists/post.json b/backend/schema/paths/nginx/access-lists/post.json index cb3af8f42..4c5a4edd2 100644 --- a/backend/schema/paths/nginx/access-lists/post.json +++ b/backend/schema/paths/nginx/access-lists/post.json @@ -93,15 +93,15 @@ "owner_user_id": 1, "name": "test1234", "meta": {}, - "satisfy_any": 1, - "pass_auth": 0, + "satisfy_any": true, + "pass_auth": false, "proxy_host_count": 0, "owner": { "id": 1, "created_on": "2024-10-07T22:43:55.000Z", "modified_on": "2024-10-08T12:52:54.000Z", - "is_deleted": 0, - "is_disabled": 0, + "is_deleted": false, + "is_disabled": false, "email": "admin@example.com", "name": "Administrator", "nickname": "some guy", diff --git a/backend/schema/paths/nginx/certificates/certID/renew/post.json b/backend/schema/paths/nginx/certificates/certID/renew/post.json index 7b32af04a..ef4d20e5b 100644 --- a/backend/schema/paths/nginx/certificates/certID/renew/post.json +++ b/backend/schema/paths/nginx/certificates/certID/renew/post.json @@ -32,7 +32,7 @@ "id": 4, "created_on": "2024-10-09T05:31:58.000Z", "owner_user_id": 1, - "is_deleted": 0, + "is_deleted": false, "provider": "letsencrypt", "nice_name": "My Test Cert", "domain_names": ["test.jc21.supernerd.pro"], diff --git a/backend/schema/paths/nginx/certificates/post.json b/backend/schema/paths/nginx/certificates/post.json index cc4d91d6d..1b2e04625 100644 --- a/backend/schema/paths/nginx/certificates/post.json +++ b/backend/schema/paths/nginx/certificates/post.json @@ -47,7 +47,7 @@ "id": 5, "created_on": "2024-10-09 05:28:35", "owner_user_id": 1, - "is_deleted": 0, + "is_deleted": false, "provider": "letsencrypt", "nice_name": "test.example.com", "domain_names": ["test.example.com"], diff --git a/backend/schema/paths/nginx/dead-hosts/get.json b/backend/schema/paths/nginx/dead-hosts/get.json index 61e2b2784..8a11a3f66 100644 --- a/backend/schema/paths/nginx/dead-hosts/get.json +++ b/backend/schema/paths/nginx/dead-hosts/get.json @@ -33,16 +33,16 @@ "owner_user_id": 1, "domain_names": ["test.example.com"], "certificate_id": 0, - "ssl_forced": 0, + "ssl_forced": false, "advanced_config": "", "meta": { "nginx_online": true, "nginx_err": null }, - "http2_support": 0, - "enabled": 1, - "hsts_enabled": 0, - "hsts_subdomains": 0 + "http2_support": false, + "enabled": true, + "hsts_enabled": false, + "hsts_subdomains": false } ] } diff --git a/backend/schema/paths/nginx/dead-hosts/hostID/get.json b/backend/schema/paths/nginx/dead-hosts/hostID/get.json index ae077c104..47e2f8b12 100644 --- a/backend/schema/paths/nginx/dead-hosts/hostID/get.json +++ b/backend/schema/paths/nginx/dead-hosts/hostID/get.json @@ -33,16 +33,16 @@ "owner_user_id": 1, "domain_names": ["test.example.com"], "certificate_id": 0, - "ssl_forced": 0, + "ssl_forced": false, "advanced_config": "", "meta": { "nginx_online": true, "nginx_err": null }, - "http2_support": 0, - "enabled": 1, - "hsts_enabled": 0, - "hsts_subdomains": 0 + "http2_support": false, + "enabled": true, + "hsts_enabled": false, + "hsts_subdomains": false } } }, diff --git a/backend/schema/paths/nginx/dead-hosts/hostID/put.json b/backend/schema/paths/nginx/dead-hosts/hostID/put.json index 058aff172..6a0a57e3a 100644 --- a/backend/schema/paths/nginx/dead-hosts/hostID/put.json +++ b/backend/schema/paths/nginx/dead-hosts/hostID/put.json @@ -72,22 +72,22 @@ "owner_user_id": 1, "domain_names": ["test.example.com"], "certificate_id": 0, - "ssl_forced": 0, + "ssl_forced": false, "advanced_config": "", "meta": { "nginx_online": true, "nginx_err": null }, - "http2_support": 0, - "enabled": 1, - "hsts_enabled": 0, - "hsts_subdomains": 0, + "http2_support": false, + "enabled": true, + "hsts_enabled": false, + "hsts_subdomains": false, "owner": { "id": 1, "created_on": "2024-10-09T00:59:56.000Z", "modified_on": "2024-10-09T00:59:56.000Z", - "is_deleted": 0, - "is_disabled": 0, + "is_deleted": false, + "is_disabled": false, "email": "admin@example.com", "name": "Administrator", "nickname": "Admin", diff --git a/backend/schema/paths/nginx/dead-hosts/post.json b/backend/schema/paths/nginx/dead-hosts/post.json index b26174361..593135065 100644 --- a/backend/schema/paths/nginx/dead-hosts/post.json +++ b/backend/schema/paths/nginx/dead-hosts/post.json @@ -60,20 +60,20 @@ "owner_user_id": 1, "domain_names": ["test.example.com"], "certificate_id": 0, - "ssl_forced": 0, + "ssl_forced": false, "advanced_config": "", "meta": {}, - "http2_support": 0, - "enabled": 1, - "hsts_enabled": 0, - "hsts_subdomains": 0, + "http2_support": false, + "enabled": true, + "hsts_enabled": false, + "hsts_subdomains": false, "certificate": null, "owner": { "id": 1, "created_on": "2024-10-09T00:59:56.000Z", "modified_on": "2024-10-09T00:59:56.000Z", - "is_deleted": 0, - "is_disabled": 0, + "is_deleted": false, + "is_disabled": false, "email": "admin@example.com", "name": "Administrator", "nickname": "Admin", diff --git a/backend/schema/paths/nginx/proxy-hosts/get.json b/backend/schema/paths/nginx/proxy-hosts/get.json index 9e9a7855b..1d9f63351 100644 --- a/backend/schema/paths/nginx/proxy-hosts/get.json +++ b/backend/schema/paths/nginx/proxy-hosts/get.json @@ -36,21 +36,21 @@ "forward_port": 8989, "access_list_id": 0, "certificate_id": 0, - "ssl_forced": 0, - "caching_enabled": 0, - "block_exploits": 0, + "ssl_forced": false, + "caching_enabled": false, + "block_exploits": false, "advanced_config": "", "meta": { "nginx_online": true, "nginx_err": null }, - "allow_websocket_upgrade": 0, - "http2_support": 0, + "allow_websocket_upgrade": false, + "http2_support": false, "forward_scheme": "http", - "enabled": 1, + "enabled": true, "locations": null, - "hsts_enabled": 0, - "hsts_subdomains": 0 + "hsts_enabled": false, + "hsts_subdomains": false } ] } diff --git a/backend/schema/paths/nginx/proxy-hosts/hostID/get.json b/backend/schema/paths/nginx/proxy-hosts/hostID/get.json index 250bf0326..5e10a9cfd 100644 --- a/backend/schema/paths/nginx/proxy-hosts/hostID/get.json +++ b/backend/schema/paths/nginx/proxy-hosts/hostID/get.json @@ -36,21 +36,21 @@ "forward_port": 8989, "access_list_id": 0, "certificate_id": 0, - "ssl_forced": 0, - "caching_enabled": 0, - "block_exploits": 0, + "ssl_forced": false, + "caching_enabled": false, + "block_exploits": false, "advanced_config": "", "meta": { "nginx_online": true, "nginx_err": null }, - "allow_websocket_upgrade": 0, - "http2_support": 0, + "allow_websocket_upgrade": false, + "http2_support": false, "forward_scheme": "http", - "enabled": 1, + "enabled": true, "locations": null, - "hsts_enabled": 0, - "hsts_subdomains": 0 + "hsts_enabled": false, + "hsts_subdomains": false } } }, diff --git a/backend/schema/paths/nginx/proxy-hosts/hostID/put.json b/backend/schema/paths/nginx/proxy-hosts/hostID/put.json index 9028c6ac5..af73905dc 100644 --- a/backend/schema/paths/nginx/proxy-hosts/hostID/put.json +++ b/backend/schema/paths/nginx/proxy-hosts/hostID/put.json @@ -102,26 +102,26 @@ "forward_port": 8989, "access_list_id": 0, "certificate_id": 0, - "ssl_forced": 0, - "caching_enabled": 0, - "block_exploits": 0, + "ssl_forced": false, + "caching_enabled": false, + "block_exploits": false, "advanced_config": "", "meta": { "nginx_online": true, "nginx_err": null }, - "allow_websocket_upgrade": 0, - "http2_support": 0, + "allow_websocket_upgrade": false, + "http2_support": false, "forward_scheme": "http", - "enabled": 1, - "hsts_enabled": 0, - "hsts_subdomains": 0, + "enabled": true, + "hsts_enabled": false, + "hsts_subdomains": false, "owner": { "id": 1, "created_on": "2024-10-07T22:43:55.000Z", "modified_on": "2024-10-08T12:52:54.000Z", - "is_deleted": 0, - "is_disabled": 0, + "is_deleted": false, + "is_disabled": false, "email": "admin@example.com", "name": "Administrator", "nickname": "some guy", diff --git a/backend/schema/paths/nginx/proxy-hosts/post.json b/backend/schema/paths/nginx/proxy-hosts/post.json index 5f61ff4c0..13f641610 100644 --- a/backend/schema/paths/nginx/proxy-hosts/post.json +++ b/backend/schema/paths/nginx/proxy-hosts/post.json @@ -90,24 +90,24 @@ "forward_port": 8989, "access_list_id": 0, "certificate_id": 0, - "ssl_forced": 0, - "caching_enabled": 0, - "block_exploits": 0, + "ssl_forced": false, + "caching_enabled": false, + "block_exploits": false, "advanced_config": "", "meta": {}, - "allow_websocket_upgrade": 0, - "http2_support": 0, + "allow_websocket_upgrade": false, + "http2_support": false, "forward_scheme": "http", - "enabled": 1, - "hsts_enabled": 0, - "hsts_subdomains": 0, + "enabled": true, + "hsts_enabled": false, + "hsts_subdomains": false, "certificate": null, "owner": { "id": 1, "created_on": "2024-10-07T22:43:55.000Z", "modified_on": "2024-10-08T12:52:54.000Z", - "is_deleted": 0, - "is_disabled": 0, + "is_deleted": false, + "is_disabled": false, "email": "admin@example.com", "name": "Administrator", "nickname": "some guy", diff --git a/backend/schema/paths/nginx/redirection-hosts/get.json b/backend/schema/paths/nginx/redirection-hosts/get.json index 24adbc78d..0b35e0fc4 100644 --- a/backend/schema/paths/nginx/redirection-hosts/get.json +++ b/backend/schema/paths/nginx/redirection-hosts/get.json @@ -33,19 +33,19 @@ "owner_user_id": 1, "domain_names": ["test.example.com"], "forward_domain_name": "something-else.com", - "preserve_path": 0, + "preserve_path": false, "certificate_id": 0, - "ssl_forced": 0, - "block_exploits": 0, + "ssl_forced": false, + "block_exploits": false, "advanced_config": "", "meta": { "nginx_online": true, "nginx_err": null }, - "http2_support": 0, - "enabled": 1, - "hsts_enabled": 0, - "hsts_subdomains": 0, + "http2_support": false, + "enabled": true, + "hsts_enabled": false, + "hsts_subdomains": false, "forward_scheme": "http", "forward_http_code": 301 } diff --git a/backend/schema/paths/nginx/redirection-hosts/hostID/get.json b/backend/schema/paths/nginx/redirection-hosts/hostID/get.json index f20ff296c..d780f874b 100644 --- a/backend/schema/paths/nginx/redirection-hosts/hostID/get.json +++ b/backend/schema/paths/nginx/redirection-hosts/hostID/get.json @@ -33,19 +33,19 @@ "owner_user_id": 1, "domain_names": ["test.example.com"], "forward_domain_name": "something-else.com", - "preserve_path": 0, + "preserve_path": false, "certificate_id": 0, - "ssl_forced": 0, - "block_exploits": 0, + "ssl_forced": false, + "block_exploits": false, "advanced_config": "", "meta": { "nginx_online": true, "nginx_err": null }, - "http2_support": 0, - "enabled": 1, - "hsts_enabled": 0, - "hsts_subdomains": 0, + "http2_support": false, + "enabled": true, + "hsts_enabled": false, + "hsts_subdomains": false, "forward_scheme": "http", "forward_http_code": 301 } diff --git a/backend/schema/paths/nginx/redirection-hosts/hostID/put.json b/backend/schema/paths/nginx/redirection-hosts/hostID/put.json index 3ee97947c..870f16fcd 100644 --- a/backend/schema/paths/nginx/redirection-hosts/hostID/put.json +++ b/backend/schema/paths/nginx/redirection-hosts/hostID/put.json @@ -87,27 +87,27 @@ "owner_user_id": 1, "domain_names": ["test.example.com"], "forward_domain_name": "something-else.com", - "preserve_path": 0, + "preserve_path": false, "certificate_id": 0, - "ssl_forced": 0, - "block_exploits": 0, + "ssl_forced": false, + "block_exploits": false, "advanced_config": "", "meta": { "nginx_online": true, "nginx_err": null }, - "http2_support": 0, - "enabled": 1, - "hsts_enabled": 0, - "hsts_subdomains": 0, + "http2_support": false, + "enabled": true, + "hsts_enabled": false, + "hsts_subdomains": false, "forward_scheme": "http", "forward_http_code": 301, "owner": { "id": 1, "created_on": "2024-10-09T00:59:56.000Z", "modified_on": "2024-10-09T00:59:56.000Z", - "is_deleted": 0, - "is_disabled": 0, + "is_deleted": false, + "is_disabled": false, "email": "admin@example.com", "name": "Administrator", "nickname": "Admin", diff --git a/backend/schema/paths/nginx/redirection-hosts/post.json b/backend/schema/paths/nginx/redirection-hosts/post.json index e8d2fa17b..3a9a05fec 100644 --- a/backend/schema/paths/nginx/redirection-hosts/post.json +++ b/backend/schema/paths/nginx/redirection-hosts/post.json @@ -75,16 +75,16 @@ "owner_user_id": 1, "domain_names": ["test.example.com"], "forward_domain_name": "something-else.com", - "preserve_path": 0, + "preserve_path": false, "certificate_id": 0, - "ssl_forced": 0, - "block_exploits": 0, + "ssl_forced": false, + "block_exploits": false, "advanced_config": "", "meta": {}, - "http2_support": 0, - "enabled": 1, - "hsts_enabled": 0, - "hsts_subdomains": 0, + "http2_support": false, + "enabled": true, + "hsts_enabled": false, + "hsts_subdomains": false, "forward_scheme": "http", "forward_http_code": 301, "certificate": null, @@ -92,8 +92,8 @@ "id": 1, "created_on": "2024-10-09T00:59:56.000Z", "modified_on": "2024-10-09T00:59:56.000Z", - "is_deleted": 0, - "is_disabled": 0, + "is_deleted": false, + "is_disabled": false, "email": "admin@example.com", "name": "Administrator", "nickname": "Admin", diff --git a/backend/schema/paths/nginx/streams/get.json b/backend/schema/paths/nginx/streams/get.json index 5ea97ce39..596afc6e7 100644 --- a/backend/schema/paths/nginx/streams/get.json +++ b/backend/schema/paths/nginx/streams/get.json @@ -34,13 +34,13 @@ "incoming_port": 9090, "forwarding_host": "router.internal", "forwarding_port": 80, - "tcp_forwarding": 0, - "udp_forwarding": 0, + "tcp_forwarding": true, + "udp_forwarding": false, "meta": { "nginx_online": true, "nginx_err": null }, - "enabled": 1 + "enabled": true } ] } diff --git a/backend/schema/paths/nginx/streams/post.json b/backend/schema/paths/nginx/streams/post.json index 0610a7273..9f3514e0f 100644 --- a/backend/schema/paths/nginx/streams/post.json +++ b/backend/schema/paths/nginx/streams/post.json @@ -55,19 +55,19 @@ "incoming_port": 9090, "forwarding_host": "router.internal", "forwarding_port": 80, - "tcp_forwarding": 0, - "udp_forwarding": 0, + "tcp_forwarding": true, + "udp_forwarding": false, "meta": { "nginx_online": true, "nginx_err": null }, - "enabled": 1, + "enabled": true, "owner": { "id": 1, "created_on": "2024-10-09T02:33:16.000Z", "modified_on": "2024-10-09T02:33:16.000Z", - "is_deleted": 0, - "is_disabled": 0, + "is_deleted": false, + "is_disabled": false, "email": "admin@example.com", "name": "Administrator", "nickname": "Admin", diff --git a/backend/schema/paths/nginx/streams/streamID/get.json b/backend/schema/paths/nginx/streams/streamID/get.json index a3371e8b8..6547656df 100644 --- a/backend/schema/paths/nginx/streams/streamID/get.json +++ b/backend/schema/paths/nginx/streams/streamID/get.json @@ -34,13 +34,13 @@ "incoming_port": 9090, "forwarding_host": "router.internal", "forwarding_port": 80, - "tcp_forwarding": 0, - "udp_forwarding": 0, + "tcp_forwarding": true, + "udp_forwarding": false, "meta": { "nginx_online": true, "nginx_err": null }, - "enabled": 1 + "enabled": true } } }, diff --git a/backend/schema/paths/nginx/streams/streamID/put.json b/backend/schema/paths/nginx/streams/streamID/put.json index cb85a6917..f3ef54d47 100644 --- a/backend/schema/paths/nginx/streams/streamID/put.json +++ b/backend/schema/paths/nginx/streams/streamID/put.json @@ -102,26 +102,26 @@ "forward_port": 8989, "access_list_id": 0, "certificate_id": 0, - "ssl_forced": 0, - "caching_enabled": 0, - "block_exploits": 0, + "ssl_forced": false, + "caching_enabled": false, + "block_exploits": false, "advanced_config": "", "meta": { "nginx_online": true, "nginx_err": null }, - "allow_websocket_upgrade": 0, - "http2_support": 0, + "allow_websocket_upgrade": false, + "http2_support": false, "forward_scheme": "http", - "enabled": 1, - "hsts_enabled": 0, - "hsts_subdomains": 0, + "enabled": true, + "hsts_enabled": false, + "hsts_subdomains": false, "owner": { "id": 1, "created_on": "2024-10-07T22:43:55.000Z", "modified_on": "2024-10-08T12:52:54.000Z", - "is_deleted": 0, - "is_disabled": 0, + "is_deleted": false, + "is_disabled": false, "email": "admin@example.com", "name": "Administrator", "nickname": "some guy", diff --git a/backend/schema/paths/users/get.json b/backend/schema/paths/users/get.json index 41a0532c3..374153011 100644 --- a/backend/schema/paths/users/get.json +++ b/backend/schema/paths/users/get.json @@ -30,7 +30,7 @@ "id": 1, "created_on": "2020-01-30T09:36:08.000Z", "modified_on": "2020-01-30T09:41:04.000Z", - "is_disabled": 0, + "is_disabled": false, "email": "jc@jc21.com", "name": "Jamie Curnow", "nickname": "James", @@ -45,7 +45,7 @@ "id": 1, "created_on": "2020-01-30T09:36:08.000Z", "modified_on": "2020-01-30T09:41:04.000Z", - "is_disabled": 0, + "is_disabled": false, "email": "jc@jc21.com", "name": "Jamie Curnow", "nickname": "James", diff --git a/backend/schema/paths/users/post.json b/backend/schema/paths/users/post.json index 1eec1b510..c0213fe05 100644 --- a/backend/schema/paths/users/post.json +++ b/backend/schema/paths/users/post.json @@ -56,7 +56,7 @@ "id": 2, "created_on": "2020-01-30T09:41:04.000Z", "modified_on": "2020-01-30T09:41:04.000Z", - "is_disabled": 0, + "is_disabled": false, "email": "jc@jc21.com", "name": "Jamie Curnow", "nickname": "James", diff --git a/backend/schema/paths/users/userID/get.json b/backend/schema/paths/users/userID/get.json index f79c92943..cb8ac61b4 100644 --- a/backend/schema/paths/users/userID/get.json +++ b/backend/schema/paths/users/userID/get.json @@ -39,7 +39,7 @@ "id": 1, "created_on": "2020-01-30T09:36:08.000Z", "modified_on": "2020-01-30T09:41:04.000Z", - "is_disabled": 0, + "is_disabled": false, "email": "jc@jc21.com", "name": "Jamie Curnow", "nickname": "James", diff --git a/backend/schema/paths/users/userID/login/post.json b/backend/schema/paths/users/userID/login/post.json index 5f247b335..6148d182b 100644 --- a/backend/schema/paths/users/userID/login/post.json +++ b/backend/schema/paths/users/userID/login/post.json @@ -34,7 +34,7 @@ "id": 1, "created_on": "2020-01-30T10:43:44.000Z", "modified_on": "2020-01-30T10:43:44.000Z", - "is_disabled": 0, + "is_disabled": false, "email": "jc@jc21.com", "name": "Jamie Curnow", "nickname": "James", diff --git a/backend/schema/paths/users/userID/put.json b/backend/schema/paths/users/userID/put.json index 54cb44b44..60a6cd132 100644 --- a/backend/schema/paths/users/userID/put.json +++ b/backend/schema/paths/users/userID/put.json @@ -69,7 +69,7 @@ "id": 2, "created_on": "2020-01-30T09:36:08.000Z", "modified_on": "2020-01-30T09:41:04.000Z", - "is_disabled": 0, + "is_disabled": false, "email": "jc@jc21.com", "name": "Jamie Curnow", "nickname": "James", diff --git a/backend/schema/swagger.json b/backend/schema/swagger.json index 9c00fa634..5a0142bff 100644 --- a/backend/schema/swagger.json +++ b/backend/schema/swagger.json @@ -1,5 +1,5 @@ { - "openapi": "3.0.0", + "openapi": "3.1.0", "info": { "title": "Nginx Proxy Manager API", "version": "2.x.x" diff --git a/backend/validate-schema.js b/backend/validate-schema.js new file mode 100644 index 000000000..71a05c818 --- /dev/null +++ b/backend/validate-schema.js @@ -0,0 +1,16 @@ +const SwaggerParser = require('@apidevtools/swagger-parser'); +const chalk = require('chalk'); +const schema = require('./schema'); +const log = console.log; + +schema.getCompiledSchema().then(async (swaggerJSON) => { + try { + const api = await SwaggerParser.validate(swaggerJSON); + console.log('API name: %s, Version: %s', api.info.title, api.info.version); + log(chalk.green('❯ Schema is valid')); + } catch (e) { + console.error(e); + log(chalk.red('❯', e.message), '\n'); + process.exit(1); + } +}); diff --git a/backend/yarn.lock b/backend/yarn.lock index 6346c14ce..be1e68e6d 100644 --- a/backend/yarn.lock +++ b/backend/yarn.lock @@ -2,12 +2,12 @@ # yarn lockfile v1 -"@apidevtools/json-schema-ref-parser@8.0.0": - version "8.0.0" - resolved "https://registry.yarnpkg.com/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-8.0.0.tgz#9eb749499b3f8d919e90bb141e4b6f67aee4692d" - integrity sha512-n4YBtwQhdpLto1BaUCyAeflizmIbaloGShsPyRtFf5qdFJxfssj+GgLavczgKJFa3Bq+3St2CKcpRJdjtB4EBw== +"@apidevtools/json-schema-ref-parser@9.0.6": + version "9.0.6" + resolved "https://registry.yarnpkg.com/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-9.0.6.tgz#5d9000a3ac1fd25404da886da6b266adcd99cf1c" + integrity sha512-M3YgsLjI0lZxvrpeGVk9Ap032W6TPQkH6pRAZz81Ac3WUNF79VQooAFnp8umjvVzUmD93NkogxEwbSce7qMsUg== dependencies: - "@jsdevtools/ono" "^7.1.0" + "@jsdevtools/ono" "^7.1.3" call-me-maybe "^1.0.1" js-yaml "^3.13.1" @@ -20,6 +20,29 @@ "@types/json-schema" "^7.0.15" js-yaml "^4.1.0" +"@apidevtools/openapi-schemas@^2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@apidevtools/openapi-schemas/-/openapi-schemas-2.1.0.tgz#9fa08017fb59d80538812f03fc7cac5992caaa17" + integrity sha512-Zc1AlqrJlX3SlpupFGpiLi2EbteyP7fXmUOGup6/DnkRgjP9bgMM/ag+n91rsv0U1Gpz0H3VILA/o3bW7Ua6BQ== + +"@apidevtools/swagger-methods@^3.0.2": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@apidevtools/swagger-methods/-/swagger-methods-3.0.2.tgz#b789a362e055b0340d04712eafe7027ddc1ac267" + integrity sha512-QAkD5kK2b1WfjDS/UQn/qQkbwF31uqRjPTrsCs5ZG9BQGAkjwvqGFjjPqAuzac/IYzpPtRzjCP1WrTuAIjMrXg== + +"@apidevtools/swagger-parser@^10.1.0": + version "10.1.0" + resolved "https://registry.yarnpkg.com/@apidevtools/swagger-parser/-/swagger-parser-10.1.0.tgz#a987d71e5be61feb623203be0c96e5985b192ab6" + integrity sha512-9Kt7EuS/7WbMAUv2gSziqjvxwDbFSg3Xeyfuj5laUODX8o/k/CpsAKiQ8W7/R88eXFTMbJYg6+7uAmOWNKmwnw== + dependencies: + "@apidevtools/json-schema-ref-parser" "9.0.6" + "@apidevtools/openapi-schemas" "^2.1.0" + "@apidevtools/swagger-methods" "^3.0.2" + "@jsdevtools/ono" "^7.1.3" + ajv "^8.6.3" + ajv-draft-04 "^1.0.0" + call-me-maybe "^1.0.1" + "@eslint-community/eslint-utils@^4.2.0": version "4.3.0" resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.3.0.tgz#a556790523a351b4e47e9d385f47265eaaf9780a" @@ -76,7 +99,7 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== -"@jsdevtools/ono@^7.1.0", "@jsdevtools/ono@^7.1.3": +"@jsdevtools/ono@^7.1.3": version "7.1.3" resolved "https://registry.yarnpkg.com/@jsdevtools/ono/-/ono-7.1.3.tgz#9df03bbd7c696a5c58885c34aa06da41c8543796" integrity sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg== @@ -207,7 +230,12 @@ aggregate-error@^3.0.0: clean-stack "^2.0.0" indent-string "^4.0.0" -ajv@^6.10.0, ajv@^6.12.0, ajv@^6.12.4: +ajv-draft-04@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/ajv-draft-04/-/ajv-draft-04-1.0.0.tgz#3b64761b268ba0b9e668f0b41ba53fce0ad77fc8" + integrity sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw== + +ajv@^6.10.0, ajv@^6.12.4: version "6.12.6" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== @@ -217,6 +245,16 @@ ajv@^6.10.0, ajv@^6.12.0, ajv@^6.12.4: json-schema-traverse "^0.4.1" uri-js "^4.2.2" +ajv@^8.17.1, ajv@^8.6.3: + version "8.17.1" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.17.1.tgz#37d9a5c776af6bc92d7f4f9510eba4c0a60d11a6" + integrity sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g== + dependencies: + fast-deep-equal "^3.1.3" + fast-uri "^3.0.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + ajv@^8.6.2: version "8.12.0" resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.12.0.tgz#d1a0527323e22f53562c567c00991577dfbe19d1" @@ -566,6 +604,14 @@ camelcase@^5.0.0, camelcase@^5.3.1: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== +chalk@4.1.2, chalk@^4.0.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + chalk@^2.3.2: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" @@ -583,14 +629,6 @@ chalk@^3.0.0: ansi-styles "^4.1.0" supports-color "^7.1.0" -chalk@^4.0.0: - version "4.1.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" - integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - chokidar@^3.2.2: version "3.4.1" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.4.1.tgz#e905bdecf10eaa0a0b1db0c664481cc4cbc22ba1" @@ -1199,6 +1237,11 @@ fast-levenshtein@^2.0.6: resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== +fast-uri@^3.0.1: + version "3.0.2" + resolved "https://registry.yarnpkg.com/fast-uri/-/fast-uri-3.0.2.tgz#d78b298cf70fd3b752fd951175a3da6a7b48f024" + integrity sha512-GR6f0hD7XXyNJa25Tb9BuIdN0tdr+0BMi6/CJPH3wJO1JjNG3n/VsSw38AwRdKZABm8lGbPfakLRkYzx2V9row== + fastq@^1.6.0: version "1.15.0" resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.15.0.tgz#d04d07c6a2a68fe4599fea8d2e103a937fae6b3a" @@ -1870,13 +1913,6 @@ json-parse-better-errors@^1.0.1: resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== -json-schema-ref-parser@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/json-schema-ref-parser/-/json-schema-ref-parser-8.0.0.tgz#7c758fac2cf822c05e837abd0a13f8fa2c15ffd4" - integrity sha512-2P4icmNkZLrBr6oa5gSZaDSol/oaBHYkoP/8dsw63E54NnHGRhhiFuy9yFoxPuSm+uHKmeGxAAWMDF16SCHhcQ== - dependencies: - "@apidevtools/json-schema-ref-parser" "8.0.0" - json-schema-traverse@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" diff --git a/test/cypress/e2e/api/Health.cy.js b/test/cypress/e2e/api/Health.cy.js index 5538916cb..f765c99b9 100644 --- a/test/cypress/e2e/api/Health.cy.js +++ b/test/cypress/e2e/api/Health.cy.js @@ -14,7 +14,7 @@ describe('Basic API checks', () => { cy.task('backendApiGet', { path: '/api/schema', }).then((data) => { - expect(data.openapi).to.be.equal('3.0.0'); + expect(data.openapi).to.be.equal('3.1.0'); }); }); }); diff --git a/test/cypress/e2e/api/Hosts.cy.js b/test/cypress/e2e/api/Hosts.cy.js index 4652c8e08..62b9581bb 100644 --- a/test/cypress/e2e/api/Hosts.cy.js +++ b/test/cypress/e2e/api/Hosts.cy.js @@ -39,7 +39,7 @@ describe('Hosts endpoints', () => { expect(data).to.have.property('id'); expect(data.id).to.be.greaterThan(0); expect(data).to.have.property('enabled'); - expect(data.enabled).to.be.greaterThan(0); + expect(data).to.have.property("enabled", true); expect(data).to.have.property('meta'); expect(typeof data.meta.nginx_online).to.be.equal('undefined'); }); diff --git a/test/cypress/plugins/backendApi/logger.js b/test/cypress/plugins/backendApi/logger.js index 98efa260e..8920b8692 100644 --- a/test/cypress/plugins/backendApi/logger.js +++ b/test/cypress/plugins/backendApi/logger.js @@ -1,12 +1,7 @@ const _ = require("lodash"); -const chalk = require("chalk"); module.exports = function() { - var arr = _.values(arguments); - arr.unshift( - chalk.blue.bold("[") + - chalk.yellow.bold("Backend API") + - chalk.blue.bold("]"), - ); + let arr = _.values(arguments); + arr.unshift('[Backend API]'); console.log.apply(null, arr); }; diff --git a/test/package.json b/test/package.json index b0f6ba79d..69b2b8613 100644 --- a/test/package.json +++ b/test/package.json @@ -6,21 +6,20 @@ "dependencies": { "@jc21/cypress-swagger-validation": "^0.2.6", "@jc21/restler": "^3.4.0", - "chalk": "^4.1.0", - "cypress": "^13.9.0", + "cypress": "^13.15.0", "cypress-multi-reporters": "^1.6.4", - "cypress-wait-until": "^3.0.1", - "eslint": "^9.3.0", + "cypress-wait-until": "^3.0.2", + "eslint": "^9.12.0", "eslint-plugin-align-assignments": "^1.1.2", - "eslint-plugin-chai-friendly": "^0.7.4", - "eslint-plugin-cypress": "^3.2.0", + "eslint-plugin-chai-friendly": "^1.0.1", + "eslint-plugin-cypress": "^3.5.0", "lodash": "^4.17.21", - "mocha": "^10.4.0", + "mocha": "^10.7.3", "mocha-junit-reporter": "^2.2.1" }, "scripts": { - "cypress": "cypress open --config-file=cypress/config/dev.json --config baseUrl=${BASE_URL:-http://127.0.0.1:3081}", - "cypress:headless": "cypress run --config-file=cypress/config/dev.json --config baseUrl=${BASE_URL:-http://127.0.0.1:3081}" + "cypress": "cypress open --config-file=cypress/config/dev.js --config baseUrl=${BASE_URL:-http://127.0.0.1:3081}", + "cypress:headless": "cypress run --config-file=cypress/config/dev.js --config baseUrl=${BASE_URL:-http://127.0.0.1:3081}" }, "author": "", "license": "ISC" diff --git a/test/yarn.lock b/test/yarn.lock index 943147b01..b34385bd2 100644 --- a/test/yarn.lock +++ b/test/yarn.lock @@ -49,10 +49,10 @@ resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9" integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ== -"@cypress/request@^3.0.0": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@cypress/request/-/request-3.0.1.tgz#72d7d5425236a2413bd3d8bb66d02d9dc3168960" - integrity sha512-TWivJlJi8ZDx2wGOw1dbLuHJKUYX7bWySw377nlnGOW3hP9/MUKIsEdXT/YngWxVdgNCHRBmFlBipE+5/2ZZlQ== +"@cypress/request@^3.0.4": + version "3.0.5" + resolved "https://registry.yarnpkg.com/@cypress/request/-/request-3.0.5.tgz#d893a6e68ce2636c085fcd8d7283c3186499ba63" + integrity sha512-v+XHd9XmWbufxF1/bTaVm2yhbxY+TB4YtWRqF2zaXBlDNMkls34KiATz0AVDLavL3iB6bQk9/7n3oY1EoLSWGA== dependencies: aws-sign2 "~0.7.0" aws4 "^1.8.0" @@ -60,14 +60,14 @@ combined-stream "~1.0.6" extend "~3.0.2" forever-agent "~0.6.1" - form-data "~2.3.2" - http-signature "~1.3.6" + form-data "~4.0.0" + http-signature "~1.4.0" is-typedarray "~1.0.0" isstream "~0.1.2" json-stringify-safe "~5.0.1" mime-types "~2.1.19" performance-now "^2.1.0" - qs "6.10.4" + qs "6.13.0" safe-buffer "^5.1.2" tough-cookie "^4.1.3" tunnel-agent "^0.6.0" @@ -88,10 +88,24 @@ dependencies: eslint-visitor-keys "^3.3.0" -"@eslint-community/regexpp@^4.6.1": - version "4.10.0" - resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.10.0.tgz#548f6de556857c8bb73bbee70c35dc82a2e74d63" - integrity sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA== +"@eslint-community/regexpp@^4.11.0": + version "4.11.1" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.11.1.tgz#a547badfc719eb3e5f4b556325e542fbe9d7a18f" + integrity sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q== + +"@eslint/config-array@^0.18.0": + version "0.18.0" + resolved "https://registry.yarnpkg.com/@eslint/config-array/-/config-array-0.18.0.tgz#37d8fe656e0d5e3dbaea7758ea56540867fd074d" + integrity sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw== + dependencies: + "@eslint/object-schema" "^2.1.4" + debug "^4.3.1" + minimatch "^3.1.2" + +"@eslint/core@^0.6.0": + version "0.6.0" + resolved "https://registry.yarnpkg.com/@eslint/core/-/core-0.6.0.tgz#9930b5ba24c406d67a1760e94cdbac616a6eb674" + integrity sha512-8I2Q8ykA4J0x0o7cg67FPVnehcqWTBehu/lmY+bolPFHGjh49YzGBMXTvpqVgEbBdvNCSxj6iFgiIyHzf03lzg== "@eslint/eslintrc@^3.1.0": version "3.1.0" @@ -108,35 +122,51 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@eslint/js@9.3.0": - version "9.3.0" - resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.3.0.tgz#2e8f65c9c55227abc4845b1513c69c32c679d8fe" - integrity sha512-niBqk8iwv96+yuTwjM6bWg8ovzAPF9qkICsGtcoa5/dmqcEMfdwNAX7+/OHcJHc7wj7XqPxH98oAHytFYlw6Sw== +"@eslint/js@9.12.0": + version "9.12.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.12.0.tgz#69ca3ca9fab9a808ec6d67b8f6edb156cbac91e1" + integrity sha512-eohesHH8WFRUprDNyEREgqP6beG6htMeUYeCpkEgBCieCMme5r9zFWjzAJp//9S+Kub4rqE+jXe9Cp1a7IYIIA== + +"@eslint/object-schema@^2.1.4": + version "2.1.4" + resolved "https://registry.yarnpkg.com/@eslint/object-schema/-/object-schema-2.1.4.tgz#9e69f8bb4031e11df79e03db09f9dbbae1740843" + integrity sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ== -"@humanwhocodes/config-array@^0.13.0": - version "0.13.0" - resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.13.0.tgz#fb907624df3256d04b9aa2df50d7aa97ec648748" - integrity sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw== +"@eslint/plugin-kit@^0.2.0": + version "0.2.0" + resolved "https://registry.yarnpkg.com/@eslint/plugin-kit/-/plugin-kit-0.2.0.tgz#8712dccae365d24e9eeecb7b346f85e750ba343d" + integrity sha512-vH9PiIMMwvhCx31Af3HiGzsVNULDbyVkHXwlemn/B0TFj/00ho3y55efXrUZTfQipxoHC5u4xq6zblww1zm1Ig== dependencies: - "@humanwhocodes/object-schema" "^2.0.3" - debug "^4.3.1" - minimatch "^3.0.5" + levn "^0.4.1" + +"@humanfs/core@^0.19.0": + version "0.19.0" + resolved "https://registry.yarnpkg.com/@humanfs/core/-/core-0.19.0.tgz#08db7a8c73bb07673d9ebd925f2dad746411fcec" + integrity sha512-2cbWIHbZVEweE853g8jymffCA+NCMiuqeECeBBLm8dg2oFdjuGJhgN4UAbI+6v0CKbbhvtXA4qV8YR5Ji86nmw== + +"@humanfs/node@^0.16.5": + version "0.16.5" + resolved "https://registry.yarnpkg.com/@humanfs/node/-/node-0.16.5.tgz#a9febb7e7ad2aff65890fdc630938f8d20aa84ba" + integrity sha512-KSPA4umqSG4LHYRodq31VDwKAvaTF4xmVlzM8Aeh4PlU1JQ3IG0wiA8C25d3RQ9nJyM3mBHyI53K06VVL/oFFg== + dependencies: + "@humanfs/core" "^0.19.0" + "@humanwhocodes/retry" "^0.3.0" "@humanwhocodes/module-importer@^1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== -"@humanwhocodes/object-schema@^2.0.3": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz#4a2868d75d6d6963e423bcf90b7fd1be343409d3" - integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA== - "@humanwhocodes/retry@^0.3.0": version "0.3.0" resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.3.0.tgz#6d86b8cb322660f03d3f0aa94b99bdd8e172d570" integrity sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew== +"@humanwhocodes/retry@^0.3.1": + version "0.3.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.3.1.tgz#c72a5c76a9fbaf3488e231b13dc52c0da7bab42a" + integrity sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA== + "@jc21/cypress-swagger-validation@^0.2.6": version "0.2.6" resolved "https://registry.yarnpkg.com/@jc21/cypress-swagger-validation/-/cypress-swagger-validation-0.2.6.tgz#8b61f2413fa81cae6f8c2f33ecce5a6ded897030" @@ -166,33 +196,17 @@ resolved "https://registry.yarnpkg.com/@jsdevtools/ono/-/ono-7.1.3.tgz#9df03bbd7c696a5c58885c34aa06da41c8543796" integrity sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg== -"@nodelib/fs.scandir@2.1.5": - version "2.1.5" - resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" - integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== - dependencies: - "@nodelib/fs.stat" "2.0.5" - run-parallel "^1.1.9" - -"@nodelib/fs.stat@2.0.5": - version "2.0.5" - resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" - integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== - -"@nodelib/fs.walk@^1.2.8": - version "1.2.8" - resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" - integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== - dependencies: - "@nodelib/fs.scandir" "2.1.5" - fastq "^1.6.0" - "@types/color-name@^1.1.1": version "1.1.1" resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0" integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ== -"@types/json-schema@^7.0.6": +"@types/estree@^1.0.6": + version "1.0.6" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.6.tgz#628effeeae2064a1b4e79f78e81d87b7e5fc7b50" + integrity sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw== + +"@types/json-schema@^7.0.15", "@types/json-schema@^7.0.6": version "7.0.15" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== @@ -229,6 +243,11 @@ acorn@^8.11.3: resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.11.3.tgz#71e0b14e13a4ec160724b38fb7b0f233b1b81d7a" integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg== +acorn@^8.12.0: + version "8.12.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.12.1.tgz#71616bdccbe25e27a54439e0046e89ca76df2248" + integrity sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg== + aggregate-error@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" @@ -262,11 +281,16 @@ ajv@^8.12.0, ajv@^8.6.3: require-from-string "^2.0.2" uri-js "^4.4.1" -ansi-colors@4.1.1, ansi-colors@^4.1.1: +ansi-colors@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== +ansi-colors@^4.1.3: + version "4.1.3" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.3.tgz#37611340eb2243e70cc604cad35d63270d48781b" + integrity sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw== + ansi-escapes@^4.3.0: version "4.3.2" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" @@ -420,7 +444,7 @@ braces@~3.0.2: dependencies: fill-range "^7.0.1" -browser-stdout@1.3.1: +browser-stdout@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== @@ -443,13 +467,16 @@ cachedir@^2.3.0: resolved "https://registry.yarnpkg.com/cachedir/-/cachedir-2.3.0.tgz#0c75892a052198f0b21c7c1804d8331edfcae0e8" integrity sha512-A+Fezp4zxnit6FanDmv9EqXNAi3vt9DWp51/71UEhXukb7QUuvtv9344h91dyAxuTLoSYJFU299qzR3tzwPAhw== -call-bind@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" - integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== +call-bind@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9" + integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w== dependencies: - function-bind "^1.1.1" - get-intrinsic "^1.0.2" + es-define-property "^1.0.0" + es-errors "^1.3.0" + function-bind "^1.1.2" + get-intrinsic "^1.2.4" + set-function-length "^1.2.1" call-me-maybe@^1.0.1: version "1.0.1" @@ -479,6 +506,11 @@ chalk@^4.0.0, chalk@^4.1.0: ansi-styles "^4.1.0" supports-color "^7.1.0" +chalk@^5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.3.0.tgz#67c20a7ebef70e7f3970a01f90fa210cb6860385" + integrity sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w== + charenc@0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667" @@ -489,10 +521,10 @@ check-more-types@^2.24.0: resolved "https://registry.yarnpkg.com/check-more-types/-/check-more-types-2.24.0.tgz#1420ffb10fd444dcfc79b43891bbfffd32a84600" integrity sha1-FCD/sQ/URNz8ebQ4kbv//TKoRgA= -chokidar@3.5.3: - version "3.5.3" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" - integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== +chokidar@^3.5.3: + version "3.6.0" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b" + integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== dependencies: anymatch "~3.1.2" braces "~3.0.2" @@ -564,7 +596,7 @@ colorette@^2.0.16: resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.19.tgz#cdf044f47ad41a0f4b56b3a0d5b4e6e1a2d5a798" integrity sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ== -combined-stream@^1.0.6, combined-stream@~1.0.6: +combined-stream@^1.0.8, combined-stream@~1.0.6: version "1.0.8" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== @@ -613,17 +645,17 @@ cypress-multi-reporters@^1.6.4: debug "^4.3.4" lodash "^4.17.21" -cypress-wait-until@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/cypress-wait-until/-/cypress-wait-until-3.0.1.tgz#6a697a600f4fb8cd2897489a15fda77c9857abec" - integrity sha512-kpoa8yL6Bi/JNsThGBbrrm7g4SNzYyBUv9M5pF6/NTVm/ClY0HnJzeuWnHiAUZKIZ5l86Oedb12wQyjx7/CWPg== +cypress-wait-until@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/cypress-wait-until/-/cypress-wait-until-3.0.2.tgz#c90dddfa4c46a2c422f5b91d486531c560bae46e" + integrity sha512-iemies796dD5CgjG5kV0MnpEmKSH+s7O83ZoJLVzuVbZmm4lheMsZqAVT73hlMx4QlkwhxbyUzhOBUOZwoOe0w== -cypress@^13.9.0: - version "13.9.0" - resolved "https://registry.yarnpkg.com/cypress/-/cypress-13.9.0.tgz#b529cfa8f8c39ba163ed0501a25bb5b09c143652" - integrity sha512-atNjmYfHsvTuCaxTxLZr9xGoHz53LLui3266WWxXJHY7+N6OdwJdg/feEa3T+buez9dmUXHT1izCOklqG82uCQ== +cypress@^13.15.0: + version "13.15.0" + resolved "https://registry.yarnpkg.com/cypress/-/cypress-13.15.0.tgz#5eca5387ef34b2e611cfa291967c69c2cd39381d" + integrity sha512-53aO7PwOfi604qzOkCSzNlWquCynLlKE/rmmpSPcziRH6LNfaDUAklQT6WJIsD8ywxlIy+uVZsnTMCCQVd2kTw== dependencies: - "@cypress/request" "^3.0.0" + "@cypress/request" "^3.0.4" "@cypress/xvfb" "^1.2.4" "@types/sinonjs__fake-timers" "8.1.1" "@types/sizzle" "^2.3.2" @@ -662,7 +694,7 @@ cypress@^13.9.0: request-progress "^3.0.0" semver "^7.5.3" supports-color "^8.1.1" - tmp "~0.2.1" + tmp "~0.2.3" untildify "^4.0.0" yauzl "^2.10.0" @@ -678,13 +710,6 @@ dayjs@^1.10.4: resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.7.tgz#4b296922642f70999544d1144a2c25730fce63e2" integrity sha512-+Yw9U6YO5TQohxLcIkrXBeY73WP3ejHWVvx8XCk3gxvQDCTEmS48ZrSZCKciI7Bhl/uCMyxYtE9UqRILmFphkQ== -debug@4.3.4, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4: - version "4.3.4" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" - integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== - dependencies: - ms "2.1.2" - debug@^3.1.0: version "3.2.6" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" @@ -699,6 +724,20 @@ debug@^4.1.1: dependencies: ms "^2.1.1" +debug@^4.3.1, debug@^4.3.2, debug@^4.3.4: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +debug@^4.3.5: + version "4.3.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.7.tgz#87945b4151a011d76d95a198d7111c865c360a52" + integrity sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ== + dependencies: + ms "^2.1.3" + decamelize@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837" @@ -709,15 +748,24 @@ deep-is@^0.1.3, deep-is@~0.1.3: resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= +define-data-property@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e" + integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A== + dependencies: + es-define-property "^1.0.0" + es-errors "^1.3.0" + gopd "^1.0.1" + delayed-stream@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= -diff@5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/diff/-/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b" - integrity sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w== +diff@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-5.2.0.tgz#26ded047cd1179b78b9537d5ef725503ce1ae531" + integrity sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A== ecc-jsbn@~0.1.1: version "0.1.2" @@ -746,21 +794,33 @@ enquirer@^2.3.6: dependencies: ansi-colors "^4.1.1" +es-define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.0.tgz#c7faefbdff8b2696cf5f46921edfb77cc4ba3845" + integrity sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ== + dependencies: + get-intrinsic "^1.2.4" + +es-errors@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" + integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== + escalade@^3.1.1: version "3.1.2" resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.2.tgz#54076e9ab29ea5bf3d8f1ed62acffbb88272df27" integrity sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA== -escape-string-regexp@4.0.0, escape-string-regexp@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" - integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== - escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= +escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + escodegen@^1.8.1: version "1.12.0" resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.12.0.tgz#f763daf840af172bb3a2b6dd7219c0e17f7ff541" @@ -778,22 +838,22 @@ eslint-plugin-align-assignments@^1.1.2: resolved "https://registry.yarnpkg.com/eslint-plugin-align-assignments/-/eslint-plugin-align-assignments-1.1.2.tgz#83e1a8a826d4adf29e82b52d0bb39c88b301b576" integrity sha512-I1ZJgk9EjHfGVU9M2Ex8UkVkkjLL5Y9BS6VNnQHq79eHj2H4/Cgxf36lQSUTLgm2ntB03A2NtF+zg9fyi5vChg== -eslint-plugin-chai-friendly@^0.7.4: - version "0.7.4" - resolved "https://registry.yarnpkg.com/eslint-plugin-chai-friendly/-/eslint-plugin-chai-friendly-0.7.4.tgz#eaf222b848673ef8a00b8e507f7c6fd83d036bf2" - integrity sha512-PGPjJ8diYgX1mjLxGJqRop2rrGwZRKImoEOwUOgoIhg0p80MkTaqvmFLe5TF7/iagZHggasvIfQlUyHIhK/PYg== +eslint-plugin-chai-friendly@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-chai-friendly/-/eslint-plugin-chai-friendly-1.0.1.tgz#c3290b5294c1145934cf9c07eaa4cec87921d18c" + integrity sha512-dxD/uz1YKJ8U4yah1i+V/p/u+kHRy3YxTPe2nJGqb5lCR+ucan/KIexfZ5+q4X+tkllyMe86EBbAkdlwxNy3oQ== -eslint-plugin-cypress@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-cypress/-/eslint-plugin-cypress-3.2.0.tgz#fe2dd9c99ed5dfed5c7be658801e75ed3d9c2265" - integrity sha512-HaxMz6BoU4ay+K4WrG9ZJC1NdX06FqSlAwtRDStjM0ORFT7zCNPNuRJ+kUPc17Rt2AMUBSqeD9L0zTR3uZhPpw== +eslint-plugin-cypress@^3.5.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-cypress/-/eslint-plugin-cypress-3.5.0.tgz#380ef5049ad80ebeca923db69e4aa96e72fcd893" + integrity sha512-JZQ6XnBTNI8h1B9M7wJSFzc48SYbh7VMMKaNTQOFa3BQlnmXPrVc4PKen8R+fpv6VleiPeej6VxloGb42zdRvw== dependencies: globals "^13.20.0" -eslint-scope@^8.0.1: - version "8.0.1" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-8.0.1.tgz#a9601e4b81a0b9171657c343fb13111688963cfc" - integrity sha512-pL8XjgP4ZOmmwfFE8mEhSxA7ZY4C+LWyqjQ3o4yWkkmD0qcMT9kkW3zWHOczhWcjTSgqycYAgwSlXvZltv65og== +eslint-scope@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-8.1.0.tgz#70214a174d4cbffbc3e8a26911d8bf51b9ae9d30" + integrity sha512-14dSvlhaVhKKsa9Fx1l8A17s7ah7Ef7wCakJ10LYk6+GYmP9yDti2oq2SEwcyndt6knfcZyhyxwY3i9yL78EQw== dependencies: esrecurse "^4.3.0" estraverse "^5.2.0" @@ -808,28 +868,37 @@ eslint-visitor-keys@^4.0.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz#e3adc021aa038a2a8e0b2f8b0ce8f66b9483b1fb" integrity sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw== -eslint@^9.3.0: - version "9.3.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-9.3.0.tgz#36a96db84592618d6ed9074d677e92f4e58c08b9" - integrity sha512-5Iv4CsZW030lpUqHBapdPo3MJetAPtejVW8B84GIcIIv8+ohFaddXsrn1Gn8uD9ijDb+kcYKFUVmC8qG8B2ORQ== +eslint-visitor-keys@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-4.1.0.tgz#1f785cc5e81eb7534523d85922248232077d2f8c" + integrity sha512-Q7lok0mqMUSf5a/AdAZkA5a/gHcO6snwQClVNNvFKCAVlxXucdU8pKydU5ZVZjBx5xr37vGbFFWtLQYreLzrZg== + +eslint@^9.12.0: + version "9.12.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-9.12.0.tgz#54fcba2876c90528396da0fa44b6446329031e86" + integrity sha512-UVIOlTEWxwIopRL1wgSQYdnVDcEvs2wyaO6DGo5mXqe3r16IoCNWkR29iHhyaP4cICWjbgbmFUGAhh0GJRuGZw== dependencies: "@eslint-community/eslint-utils" "^4.2.0" - "@eslint-community/regexpp" "^4.6.1" + "@eslint-community/regexpp" "^4.11.0" + "@eslint/config-array" "^0.18.0" + "@eslint/core" "^0.6.0" "@eslint/eslintrc" "^3.1.0" - "@eslint/js" "9.3.0" - "@humanwhocodes/config-array" "^0.13.0" + "@eslint/js" "9.12.0" + "@eslint/plugin-kit" "^0.2.0" + "@humanfs/node" "^0.16.5" "@humanwhocodes/module-importer" "^1.0.1" - "@humanwhocodes/retry" "^0.3.0" - "@nodelib/fs.walk" "^1.2.8" + "@humanwhocodes/retry" "^0.3.1" + "@types/estree" "^1.0.6" + "@types/json-schema" "^7.0.15" ajv "^6.12.4" chalk "^4.0.0" cross-spawn "^7.0.2" debug "^4.3.2" escape-string-regexp "^4.0.0" - eslint-scope "^8.0.1" - eslint-visitor-keys "^4.0.0" - espree "^10.0.1" - esquery "^1.4.2" + eslint-scope "^8.1.0" + eslint-visitor-keys "^4.1.0" + espree "^10.2.0" + esquery "^1.5.0" esutils "^2.0.2" fast-deep-equal "^3.1.3" file-entry-cache "^8.0.0" @@ -838,14 +907,11 @@ eslint@^9.3.0: ignore "^5.2.0" imurmurhash "^0.1.4" is-glob "^4.0.0" - is-path-inside "^3.0.3" json-stable-stringify-without-jsonify "^1.0.1" - levn "^0.4.1" lodash.merge "^4.6.2" minimatch "^3.1.2" natural-compare "^1.4.0" optionator "^0.9.3" - strip-ansi "^6.0.1" text-table "^0.2.0" espree@^10.0.1: @@ -857,6 +923,15 @@ espree@^10.0.1: acorn-jsx "^5.3.2" eslint-visitor-keys "^4.0.0" +espree@^10.2.0: + version "10.2.0" + resolved "https://registry.yarnpkg.com/espree/-/espree-10.2.0.tgz#f4bcead9e05b0615c968e85f83816bc386a45df6" + integrity sha512-upbkBJbckcCNBDBDXEbuhjbP68n+scUd3k/U2EkyM9nw+I/jPiL4cLF/Al06CF96wRltFda16sxDFrxsI1v0/g== + dependencies: + acorn "^8.12.0" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^4.1.0" + esprima@1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/esprima/-/esprima-1.2.2.tgz#76a0fd66fcfe154fd292667dc264019750b1657b" @@ -872,10 +947,10 @@ esprima@^4.0.0: resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== -esquery@^1.4.2: - version "1.5.0" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.5.0.tgz#6ce17738de8577694edd7361c57182ac8cb0db0b" - integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg== +esquery@^1.5.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.6.0.tgz#91419234f804d852a82dceec3e16cdc22cf9dae7" + integrity sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg== dependencies: estraverse "^5.1.0" @@ -974,13 +1049,6 @@ fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6: resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= -fastq@^1.6.0: - version "1.17.1" - resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.17.1.tgz#2a523f07a4e7b1e81a42b91b8bf2254107753b47" - integrity sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w== - dependencies: - reusify "^1.0.4" - fd-slicer@~1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e" @@ -1009,7 +1077,7 @@ fill-range@^7.0.1: dependencies: to-regex-range "^5.0.1" -find-up@5.0.0, find-up@^5.0.0: +find-up@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== @@ -1040,13 +1108,13 @@ forever-agent@~0.6.1: resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= -form-data@~2.3.2: - version "2.3.3" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" - integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== +form-data@~4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" + integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== dependencies: asynckit "^0.4.0" - combined-stream "^1.0.6" + combined-stream "^1.0.8" mime-types "^2.1.12" fs-extra@^9.1.0: @@ -1069,24 +1137,26 @@ fsevents@~2.3.2: resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== -function-bind@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" - integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== get-caller-file@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== -get-intrinsic@^1.0.2: - version "1.2.0" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.0.tgz#7ad1dc0535f3a2904bba075772763e5051f6d05f" - integrity sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q== +get-intrinsic@^1.1.3, get-intrinsic@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd" + integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ== dependencies: - function-bind "^1.1.1" - has "^1.0.3" + es-errors "^1.3.0" + function-bind "^1.1.2" + has-proto "^1.0.1" has-symbols "^1.0.3" + hasown "^2.0.0" get-stream@^5.0.0, get-stream@^5.1.0: version "5.2.0" @@ -1123,7 +1193,7 @@ glob-parent@~5.1.2: dependencies: is-glob "^4.0.1" -glob@8.1.0: +glob@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/glob/-/glob-8.1.0.tgz#d388f656593ef708ee3e34640fdfb99a9fd1c33e" integrity sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ== @@ -1134,18 +1204,6 @@ glob@8.1.0: minimatch "^5.0.1" once "^1.3.0" -glob@^7.1.3: - version "7.1.6" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" - integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - global-dirs@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-3.0.1.tgz#0c488971f066baceda21447aecb1a8b911d22485" @@ -1165,6 +1223,13 @@ globals@^14.0.0: resolved "https://registry.yarnpkg.com/globals/-/globals-14.0.0.tgz#898d7413c29babcf6bafe56fcadded858ada724e" integrity sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ== +gopd@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" + integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== + dependencies: + get-intrinsic "^1.1.3" + graceful-fs@^4.1.6, graceful-fs@^4.2.0: version "4.2.3" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.3.tgz#4a12ff1b60376ef09862c2093edd908328be8423" @@ -1175,31 +1240,43 @@ has-flag@^4.0.0: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== +has-property-descriptors@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854" + integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg== + dependencies: + es-define-property "^1.0.0" + +has-proto@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.3.tgz#b31ddfe9b0e6e9914536a6ab286426d0214f77fd" + integrity sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q== + has-symbols@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== -has@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" - integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== +hasown@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" + integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== dependencies: - function-bind "^1.1.1" + function-bind "^1.1.2" -he@1.2.0: +he@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== -http-signature@~1.3.6: - version "1.3.6" - resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.3.6.tgz#cb6fbfdf86d1c974f343be94e87f7fc128662cf9" - integrity sha512-3adrsD6zqo4GsTqtO7FyrejHNv+NgiIfAfv68+jVlFmSr9OGy7zrxONceFRLKvnnZA5jbxQBX1u9PpB6Wi32Gw== +http-signature@~1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.4.0.tgz#dee5a9ba2bf49416abc544abd6d967f6a94c8c3f" + integrity sha512-G5akfn7eKbpDN+8nPS/cb57YeA1jLTVxjpCj7tmm3QKPdyDy7T+qSC40e9ptydSWvkwjSXw1VbkpyEm39ukeAg== dependencies: assert-plus "^1.0.0" jsprim "^2.0.2" - sshpk "^1.14.1" + sshpk "^1.18.0" human-signals@^1.1.1: version "1.1.1" @@ -1313,7 +1390,7 @@ is-number@^7.0.0: resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== -is-path-inside@^3.0.2, is-path-inside@^3.0.3: +is-path-inside@^3.0.2: version "3.0.3" resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== @@ -1348,13 +1425,6 @@ isstream@~0.1.2: resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= -js-yaml@4.1.0, js-yaml@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" - integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== - dependencies: - argparse "^2.0.1" - js-yaml@^3.13.1: version "3.13.1" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" @@ -1363,6 +1433,13 @@ js-yaml@^3.13.1: argparse "^1.0.7" esprima "^4.0.0" +js-yaml@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + jsbn@~0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" @@ -1497,7 +1574,7 @@ lodash@^4.17.21: resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== -log-symbols@4.1.0, log-symbols@^4.0.0: +log-symbols@^4.0.0, log-symbols@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== @@ -1546,28 +1623,14 @@ mimic-fn@^2.1.0: resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== -minimatch@5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.0.1.tgz#fb9022f7528125187c92bd9e9b6366be1cf3415b" - integrity sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g== - dependencies: - brace-expansion "^2.0.1" - -minimatch@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" - integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== - dependencies: - brace-expansion "^1.1.7" - -minimatch@^3.0.5, minimatch@^3.1.2: +minimatch@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== dependencies: brace-expansion "^1.1.7" -minimatch@^5.0.1: +minimatch@^5.0.1, minimatch@^5.1.6: version "5.1.6" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96" integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g== @@ -1595,38 +1658,38 @@ mocha-junit-reporter@^2.2.1: strip-ansi "^6.0.1" xml "^1.0.1" -mocha@^10.4.0: - version "10.4.0" - resolved "https://registry.yarnpkg.com/mocha/-/mocha-10.4.0.tgz#ed03db96ee9cfc6d20c56f8e2af07b961dbae261" - integrity sha512-eqhGB8JKapEYcC4ytX/xrzKforgEc3j1pGlAXVy3eRwrtAy5/nIfT1SvgGzfN0XZZxeLq0aQWkOUAmqIJiv+bA== - dependencies: - ansi-colors "4.1.1" - browser-stdout "1.3.1" - chokidar "3.5.3" - debug "4.3.4" - diff "5.0.0" - escape-string-regexp "4.0.0" - find-up "5.0.0" - glob "8.1.0" - he "1.2.0" - js-yaml "4.1.0" - log-symbols "4.1.0" - minimatch "5.0.1" - ms "2.1.3" - serialize-javascript "6.0.0" - strip-json-comments "3.1.1" - supports-color "8.1.1" - workerpool "6.2.1" - yargs "16.2.0" - yargs-parser "20.2.4" - yargs-unparser "2.0.0" +mocha@^10.7.3: + version "10.7.3" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-10.7.3.tgz#ae32003cabbd52b59aece17846056a68eb4b0752" + integrity sha512-uQWxAu44wwiACGqjbPYmjo7Lg8sFrS3dQe7PP2FQI+woptP4vZXSMcfMyFL/e1yFEeEpV4RtyTpZROOKmxis+A== + dependencies: + ansi-colors "^4.1.3" + browser-stdout "^1.3.1" + chokidar "^3.5.3" + debug "^4.3.5" + diff "^5.2.0" + escape-string-regexp "^4.0.0" + find-up "^5.0.0" + glob "^8.1.0" + he "^1.2.0" + js-yaml "^4.1.0" + log-symbols "^4.1.0" + minimatch "^5.1.6" + ms "^2.1.3" + serialize-javascript "^6.0.2" + strip-json-comments "^3.1.1" + supports-color "^8.1.1" + workerpool "^6.5.1" + yargs "^16.2.0" + yargs-parser "^20.2.9" + yargs-unparser "^2.0.0" ms@2.1.2, ms@^2.1.1: version "2.1.2" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@2.1.3: +ms@^2.1.3: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== @@ -1648,10 +1711,10 @@ npm-run-path@^4.0.0: dependencies: path-key "^3.0.0" -object-inspect@^1.9.0: - version "1.12.3" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.3.tgz#ba62dffd67ee256c8c086dfae69e016cd1f198b9" - integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g== +object-inspect@^1.13.1: + version "1.13.2" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.2.tgz#dea0088467fb991e67af4058147a24824a3043ff" + integrity sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g== once@^1.3.0, once@^1.3.1, once@^1.4.0: version "1.4.0" @@ -1734,11 +1797,6 @@ path-exists@^4.0.0: resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== -path-is-absolute@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= - path-key@^3.0.0, path-key@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" @@ -1822,23 +1880,18 @@ qs@1.2.0: resolved "https://registry.yarnpkg.com/qs/-/qs-1.2.0.tgz#ed079be28682147e6fd9a34cc2b0c1e0ec6453ee" integrity sha1-7Qeb4oaCFH5v2aNMwrDB4OxkU+4= -qs@6.10.4: - version "6.10.4" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.10.4.tgz#6a3003755add91c0ec9eacdc5f878b034e73f9e7" - integrity sha512-OQiU+C+Ds5qiH91qh/mg0w+8nwQuLjM4F4M/PbmhDOoYehPh+Fb0bDjtR1sOvy7YKxvj28Y/M0PhP5uVX0kB+g== +qs@6.13.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.13.0.tgz#6ca3bd58439f7e245655798997787b0d88a51906" + integrity sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg== dependencies: - side-channel "^1.0.4" + side-channel "^1.0.6" querystringify@^2.1.1: version "2.2.0" resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6" integrity sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ== -queue-microtask@^1.2.2: - version "1.2.3" - resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" - integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== - randombytes@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" @@ -1888,30 +1941,11 @@ restore-cursor@^3.1.0: onetime "^5.1.0" signal-exit "^3.0.2" -reusify@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" - integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== - rfdc@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b" integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA== -rimraf@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" - integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== - dependencies: - glob "^7.1.3" - -run-parallel@^1.1.9: - version "1.2.0" - resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" - integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== - dependencies: - queue-microtask "^1.2.2" - rxjs@^7.5.1: version "7.8.0" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.0.tgz#90a938862a82888ff4c7359811a595e14e1e09a4" @@ -1944,13 +1978,25 @@ semver@^7.5.3: resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.2.tgz#1e3b34759f896e8f14d6134732ce798aeb0c6e13" integrity sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w== -serialize-javascript@6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.0.tgz#efae5d88f45d7924141da8b5c3a7a7e663fefeb8" - integrity sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag== +serialize-javascript@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.2.tgz#defa1e055c83bf6d59ea805d8da862254eb6a6c2" + integrity sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g== dependencies: randombytes "^2.1.0" +set-function-length@^1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449" + integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg== + dependencies: + define-data-property "^1.1.4" + es-errors "^1.3.0" + function-bind "^1.1.2" + get-intrinsic "^1.2.4" + gopd "^1.0.1" + has-property-descriptors "^1.0.2" + shebang-command@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" @@ -1963,14 +2009,15 @@ shebang-regex@^3.0.0: resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== -side-channel@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" - integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== +side-channel@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2" + integrity sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA== dependencies: - call-bind "^1.0.0" - get-intrinsic "^1.0.2" - object-inspect "^1.9.0" + call-bind "^1.0.7" + es-errors "^1.3.0" + get-intrinsic "^1.2.4" + object-inspect "^1.13.1" signal-exit@^3.0.2: version "3.0.2" @@ -2005,10 +2052,10 @@ sprintf-js@~1.0.2: resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= -sshpk@^1.14.1: - version "1.17.0" - resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.17.0.tgz#578082d92d4fe612b13007496e543fa0fbcbe4c5" - integrity sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ== +sshpk@^1.18.0: + version "1.18.0" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.18.0.tgz#1663e55cddf4d688b86a46b77f0d5fe363aba028" + integrity sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ== dependencies: asn1 "~0.2.3" assert-plus "^1.0.0" @@ -2064,18 +2111,11 @@ strip-final-newline@^2.0.0: resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== -strip-json-comments@3.1.1, strip-json-comments@^3.1.1: +strip-json-comments@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== -supports-color@8.1.1, supports-color@^8.1.1: - version "8.1.1" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" - integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== - dependencies: - has-flag "^4.0.0" - supports-color@^7.1.0: version "7.1.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.1.0.tgz#68e32591df73e25ad1c4b49108a2ec507962bfd1" @@ -2083,6 +2123,13 @@ supports-color@^7.1.0: dependencies: has-flag "^4.0.0" +supports-color@^8.1.1: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + text-table@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" @@ -2098,12 +2145,10 @@ through@^2.3.8: resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== -tmp@~0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.1.tgz#8457fc3037dcf4719c251367a1af6500ee1ccf14" - integrity sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ== - dependencies: - rimraf "^3.0.0" +tmp@~0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.3.tgz#eb783cc22bc1e8bebd0671476d46ea4eb32a79ae" + integrity sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w== to-regex-range@^5.0.1: version "5.0.1" @@ -2236,10 +2281,10 @@ word-wrap@~1.2.3: resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.4.tgz#cb4b50ec9aca570abd1f52f33cd45b6c61739a9f" integrity sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA== -workerpool@6.2.1: - version "6.2.1" - resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.2.1.tgz#46fc150c17d826b86a008e5a4508656777e9c343" - integrity sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw== +workerpool@^6.5.1: + version "6.5.1" + resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.5.1.tgz#060f73b39d0caf97c6db64da004cd01b4c099544" + integrity sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA== wrap-ansi@^6.2.0: version "6.2.0" @@ -2292,17 +2337,12 @@ yaml@0.2.3: resolved "https://registry.yarnpkg.com/yaml/-/yaml-0.2.3.tgz#b5450e92e76ef36b5dd24e3660091ebaeef3e5c7" integrity sha1-tUUOkudu82td0k42YAkeuu7z5cc= -yargs-parser@20.2.4: - version "20.2.4" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54" - integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA== - -yargs-parser@^20.2.2: +yargs-parser@^20.2.2, yargs-parser@^20.2.9: version "20.2.9" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== -yargs-unparser@2.0.0: +yargs-unparser@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-2.0.0.tgz#f131f9226911ae5d9ad38c432fe809366c2325eb" integrity sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA== @@ -2312,7 +2352,7 @@ yargs-unparser@2.0.0: flat "^5.0.2" is-plain-obj "^2.1.0" -yargs@16.2.0: +yargs@^16.2.0: version "16.2.0" resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== From 7c97516de673511c570dea12eee066af85fca1d5 Mon Sep 17 00:00:00 2001 From: Jamie Curnow Date: Thu, 10 Oct 2024 16:31:19 +1000 Subject: [PATCH 3/5] Fix schema issue with cors --- backend/lib/access.js | 2 +- backend/lib/express/cors.js | 42 ++++++++----------------------------- 2 files changed, 10 insertions(+), 34 deletions(-) diff --git a/backend/lib/access.js b/backend/lib/access.js index 57dd379c8..0e658a656 100644 --- a/backend/lib/access.js +++ b/backend/lib/access.js @@ -268,6 +268,7 @@ module.exports = function (token_string) { let permissionSchema = { $async: true, $id: 'permissions', + type: 'object', additionalProperties: false, properties: {} }; @@ -277,7 +278,6 @@ module.exports = function (token_string) { const ajv = new Ajv({ verbose: true, allErrors: true, - missingRefs: 'fail', breakOnError: true, coerceTypes: true, schemas: [ diff --git a/backend/lib/express/cors.js b/backend/lib/express/cors.js index c9befeec8..6d5b8b5fb 100644 --- a/backend/lib/express/cors.js +++ b/backend/lib/express/cors.js @@ -1,40 +1,16 @@ -const validator = require('../validator'); - module.exports = function (req, res, next) { - if (req.headers.origin) { - - const originSchema = { - oneOf: [ - { - type: 'string', - pattern: '^[a-z\\-]+:\\/\\/(?:[\\w\\-\\.]+(:[0-9]+)?/?)?$' - }, - { - type: 'string', - pattern: '^[a-z\\-]+:\\/\\/(?:\\[([a-z0-9]{0,4}\\:?)+\\])?/?(:[0-9]+)?$' - } - ] - }; - - // very relaxed validation.... - validator(originSchema, req.headers.origin) - .then(function () { - res.set({ - 'Access-Control-Allow-Origin': req.headers.origin, - 'Access-Control-Allow-Credentials': true, - 'Access-Control-Allow-Methods': 'OPTIONS, GET, POST', - 'Access-Control-Allow-Headers': 'Content-Type, Cache-Control, Pragma, Expires, Authorization, X-Dataset-Total, X-Dataset-Offset, X-Dataset-Limit', - 'Access-Control-Max-Age': 5 * 60, - 'Access-Control-Expose-Headers': 'X-Dataset-Total, X-Dataset-Offset, X-Dataset-Limit' - }); - next(); - }) - .catch(next); - + res.set({ + 'Access-Control-Allow-Origin': req.headers.origin, + 'Access-Control-Allow-Credentials': true, + 'Access-Control-Allow-Methods': 'OPTIONS, GET, POST', + 'Access-Control-Allow-Headers': 'Content-Type, Cache-Control, Pragma, Expires, Authorization, X-Dataset-Total, X-Dataset-Offset, X-Dataset-Limit', + 'Access-Control-Max-Age': 5 * 60, + 'Access-Control-Expose-Headers': 'X-Dataset-Total, X-Dataset-Offset, X-Dataset-Limit' + }); + next(); } else { // No origin next(); } - }; From c39d5433bcd13993def222bbb2b6988bbb810a05 Mon Sep 17 00:00:00 2001 From: Jamie Curnow Date: Fri, 11 Oct 2024 11:21:22 +1000 Subject: [PATCH 4/5] Fix CVE-2024-46256 and CVE-2024-46257 - Schema validate against bad domain characters - Integration test for CVE POC examples - Cypress rewrite of plugins for file upload --- backend/schema/common.json | 2 +- backend/schema/components/error.json | 9 + .../schema/paths/nginx/certificates/post.json | 20 ++ .../nginx/certificates/validate/post.json | 39 ++++ .../nginx/dead-hosts/hostID/disable/post.json | 2 +- .../nginx/dead-hosts/hostID/enable/post.json | 2 +- .../proxy-hosts/hostID/disable/post.json | 2 +- .../nginx/proxy-hosts/hostID/enable/post.json | 2 +- .../hostID/disable/post.json | 2 +- .../redirection-hosts/hostID/enable/post.json | 2 +- .../nginx/streams/streamID/disable/post.json | 2 +- .../nginx/streams/streamID/enable/post.json | 2 +- test/cypress/e2e/api/Certificates.cy.js | 50 +++++ .../cypress/fixtures/test.example.com-key.pem | 28 +++ test/cypress/fixtures/test.example.com.pem | 26 +++ test/cypress/plugins/backendApi/client.js | 182 +++++++++--------- test/cypress/plugins/backendApi/task.js | 32 ++- test/package.json | 7 +- test/yarn.lock | 117 ++++++----- 19 files changed, 353 insertions(+), 175 deletions(-) create mode 100644 backend/schema/components/error.json create mode 100644 test/cypress/e2e/api/Certificates.cy.js create mode 100644 test/cypress/fixtures/test.example.com-key.pem create mode 100644 test/cypress/fixtures/test.example.com.pem diff --git a/backend/schema/common.json b/backend/schema/common.json index ebeb34416..83de0143c 100644 --- a/backend/schema/common.json +++ b/backend/schema/common.json @@ -76,7 +76,7 @@ "uniqueItems": true, "items": { "type": "string", - "pattern": "^(?:\\*\\.)?(?:[^.*]+\\.?)+[^.]$" + "pattern": "^[^&| @!#%^();:/\\\\}{=+?<>,~`'\"]+$" } }, "enabled": { diff --git a/backend/schema/components/error.json b/backend/schema/components/error.json new file mode 100644 index 000000000..ceb3e1492 --- /dev/null +++ b/backend/schema/components/error.json @@ -0,0 +1,9 @@ +{ + "type": "object", + "description": "Error", + "properties": { + "error": { + "$ref": "./error-object.json" + } + } +} diff --git a/backend/schema/paths/nginx/certificates/post.json b/backend/schema/paths/nginx/certificates/post.json index 1b2e04625..5a3306c22 100644 --- a/backend/schema/paths/nginx/certificates/post.json +++ b/backend/schema/paths/nginx/certificates/post.json @@ -72,6 +72,26 @@ } } } + }, + "400": { + "description": "400 response", + "content": { + "application/json": { + "examples": { + "default": { + "value": { + "error": { + "code": 400, + "message": "Domains are invalid" + } + } + } + }, + "schema": { + "$ref": "../../../components/error.json" + } + } + } } } } diff --git a/backend/schema/paths/nginx/certificates/validate/post.json b/backend/schema/paths/nginx/certificates/validate/post.json index 94f02f593..21eb325ef 100644 --- a/backend/schema/paths/nginx/certificates/validate/post.json +++ b/backend/schema/paths/nginx/certificates/validate/post.json @@ -50,6 +50,42 @@ "certificate_key": true } } + }, + "schema": { + "type": "object", + "additionalProperties": false, + "required": ["certificate", "certificate_key"], + "properties": { + "certificate": { + "type": "object", + "additionalProperties": false, + "required": ["cn", "issuer", "dates"], + "properties": { + "cn": { + "type": "string" + }, + "issuer": { + "type": "string" + }, + "dates": { + "type": "object", + "additionalProperties": false, + "required": ["from", "to"], + "properties": { + "from": { + "type": "integer" + }, + "to": { + "type": "integer" + } + } + } + } + }, + "certificate_key": { + "type": "boolean" + } + } } } } @@ -67,6 +103,9 @@ } } } + }, + "schema": { + "$ref": "../../../../components/error.json" } } } diff --git a/backend/schema/paths/nginx/dead-hosts/hostID/disable/post.json b/backend/schema/paths/nginx/dead-hosts/hostID/disable/post.json index 528d05d35..2cdcecf4b 100644 --- a/backend/schema/paths/nginx/dead-hosts/hostID/disable/post.json +++ b/backend/schema/paths/nginx/dead-hosts/hostID/disable/post.json @@ -50,7 +50,7 @@ } }, "schema": { - "$ref": "../../../../../components/error-object.json" + "$ref": "../../../../../components/error.json" } } } diff --git a/backend/schema/paths/nginx/dead-hosts/hostID/enable/post.json b/backend/schema/paths/nginx/dead-hosts/hostID/enable/post.json index dd95943a5..ca3ce9fae 100644 --- a/backend/schema/paths/nginx/dead-hosts/hostID/enable/post.json +++ b/backend/schema/paths/nginx/dead-hosts/hostID/enable/post.json @@ -50,7 +50,7 @@ } }, "schema": { - "$ref": "../../../../../components/error-object.json" + "$ref": "../../../../../components/error.json" } } } diff --git a/backend/schema/paths/nginx/proxy-hosts/hostID/disable/post.json b/backend/schema/paths/nginx/proxy-hosts/hostID/disable/post.json index 1ff95e8f9..54ff8a663 100644 --- a/backend/schema/paths/nginx/proxy-hosts/hostID/disable/post.json +++ b/backend/schema/paths/nginx/proxy-hosts/hostID/disable/post.json @@ -50,7 +50,7 @@ } }, "schema": { - "$ref": "../../../../../components/error-object.json" + "$ref": "../../../../../components/error.json" } } } diff --git a/backend/schema/paths/nginx/proxy-hosts/hostID/enable/post.json b/backend/schema/paths/nginx/proxy-hosts/hostID/enable/post.json index 3a5694b9c..9f052de05 100644 --- a/backend/schema/paths/nginx/proxy-hosts/hostID/enable/post.json +++ b/backend/schema/paths/nginx/proxy-hosts/hostID/enable/post.json @@ -50,7 +50,7 @@ } }, "schema": { - "$ref": "../../../../../components/error-object.json" + "$ref": "../../../../../components/error.json" } } } diff --git a/backend/schema/paths/nginx/redirection-hosts/hostID/disable/post.json b/backend/schema/paths/nginx/redirection-hosts/hostID/disable/post.json index 7531ac36b..8433220d5 100644 --- a/backend/schema/paths/nginx/redirection-hosts/hostID/disable/post.json +++ b/backend/schema/paths/nginx/redirection-hosts/hostID/disable/post.json @@ -50,7 +50,7 @@ } }, "schema": { - "$ref": "../../../../../components/error-object.json" + "$ref": "../../../../../components/error.json" } } } diff --git a/backend/schema/paths/nginx/redirection-hosts/hostID/enable/post.json b/backend/schema/paths/nginx/redirection-hosts/hostID/enable/post.json index 60f4fafd6..bef53436b 100644 --- a/backend/schema/paths/nginx/redirection-hosts/hostID/enable/post.json +++ b/backend/schema/paths/nginx/redirection-hosts/hostID/enable/post.json @@ -50,7 +50,7 @@ } }, "schema": { - "$ref": "../../../../../components/error-object.json" + "$ref": "../../../../../components/error.json" } } } diff --git a/backend/schema/paths/nginx/streams/streamID/disable/post.json b/backend/schema/paths/nginx/streams/streamID/disable/post.json index 91c58bb80..d1c1b1c84 100644 --- a/backend/schema/paths/nginx/streams/streamID/disable/post.json +++ b/backend/schema/paths/nginx/streams/streamID/disable/post.json @@ -50,7 +50,7 @@ } }, "schema": { - "$ref": "../../../../../components/error-object.json" + "$ref": "../../../../../components/error.json" } } } diff --git a/backend/schema/paths/nginx/streams/streamID/enable/post.json b/backend/schema/paths/nginx/streams/streamID/enable/post.json index b14a86f86..dc914f5f2 100644 --- a/backend/schema/paths/nginx/streams/streamID/enable/post.json +++ b/backend/schema/paths/nginx/streams/streamID/enable/post.json @@ -50,7 +50,7 @@ } }, "schema": { - "$ref": "../../../../../components/error-object.json" + "$ref": "../../../../../components/error.json" } } } diff --git a/test/cypress/e2e/api/Certificates.cy.js b/test/cypress/e2e/api/Certificates.cy.js new file mode 100644 index 000000000..043680f3e --- /dev/null +++ b/test/cypress/e2e/api/Certificates.cy.js @@ -0,0 +1,50 @@ +/// + +describe('Certificates endpoints', () => { + let token; + + before(() => { + cy.getToken().then((tok) => { + token = tok; + }); + }); + + it('Validate custom certificate', function() { + cy.task('backendApiPostFiles', { + token: token, + path: '/api/nginx/certificates/validate', + files: { + certificate: 'test.example.com.pem', + certificate_key: 'test.example.com-key.pem', + }, + }).then((data) => { + cy.validateSwaggerSchema('post', 200, '/nginx/certificates/validate', data); + expect(data).to.have.property('certificate'); + expect(data).to.have.property('certificate_key'); + }); + }); + + it('Request Certificate - CVE-2024-46256/CVE-2024-46257', function() { + cy.task('backendApiPost', { + token: token, + path: '/api/nginx/certificates', + data: { + domain_names: ['test.com"||echo hello-world||\\\\n test.com"'], + meta: { + dns_challenge: false, + letsencrypt_agree: true, + letsencrypt_email: 'admin@example.com', + }, + provider: 'letsencrypt', + }, + returnOnError: true, + }).then((data) => { + cy.validateSwaggerSchema('post', 400, '/nginx/certificates', data); + expect(data).to.have.property('error'); + expect(data.error).to.have.property('message'); + expect(data.error).to.have.property('code'); + expect(data.error.code).to.equal(400); + expect(data.error.message).to.contain('data/domain_names/0 must match pattern'); + }); + }); +}); diff --git a/test/cypress/fixtures/test.example.com-key.pem b/test/cypress/fixtures/test.example.com-key.pem new file mode 100644 index 000000000..307cdc307 --- /dev/null +++ b/test/cypress/fixtures/test.example.com-key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC1n9j9C5Bes1nd +qACDckERauxXVNKCnUlUM1buGBx1xc+j2e2Ar23wUJJuWBY18VfT8yqfqVDktO2w +rbmvZvLuPmXePOKbIKS+XXh+2NG9L5bDG9rwGFCRXnbQj+GWCdMfzx14+CR1IHge +Yz6Cv/Si2/LJPCh/CoBfM4hUQJON3lxAWrWBpdbZnKYMrxuPBRfW9OuzTbCVXToQ +oxRAHiOR9081Xn1WeoKr7kVBIa5UphlvWXa12w1YmUwJu7YndnJGIavLWeNCVc7Z +Eo+nS8Wr/4QWicatIWZXpVaEOPhRoeplQDxNWg5b/Q26rYoVd7PrCmRs7sVcH79X +zGONeH1PAgMBAAECggEAANb3Wtwl07pCjRrMvc7WbC0xYIn82yu8/g2qtjkYUJcU +ia5lQbYN7RGCS85Oc/tkq48xQEG5JQWNH8b918jDEMTrFab0aUEyYcru1q9L8PL6 +YHaNgZSrMrDcHcS8h0QOXNRJT5jeGkiHJaTR0irvB526tqF3knbK9yW22KTfycUe +a0Z9voKn5xRk1DCbHi/nk2EpT7xnjeQeLFaTIRXbS68omkr4YGhwWm5OizoyEGZu +W0Zum5BkQyMr6kor3wdxOTG97ske2rcyvvHi+ErnwL0xBv0qY0Dhe8DpuXpDezqw +o72yY8h31Fu84i7sAj24YuE5Df8DozItFXQpkgbQ6QKBgQDPrufhvIFm2S/MzBdW +H8JxY7CJlJPyxOvc1NIl9RczQGAQR90kx52cgIcuIGEG6/wJ/xnGfMmW40F0DnQ+ +N+oLgB9SFxeLkRb7s9Z/8N3uIN8JJFYcerEOiRQeN2BXEEWJ7bUThNtsVrAcKoUh +ELsDmnHW/3V+GKwhd0vpk842+wKBgQDf4PGLG9PTE5tlAoyHFodJRd2RhTJQkwsU +MDNjLJ+KecLv+Nl+QiJhoflG1ccqtSFlBSCG067CDQ5LV0xm3mLJ7pfJoMgjcq31 +qjEmX4Ls91GuVOPtbwst3yFKjsHaSoKB5fBvWRcKFpBUezM7Qcw2JP3+dQT+bQIq +cMTkRWDSvQKBgQDOdCQFDjxg/lR7NQOZ1PaZe61aBz5P3pxNqa7ClvMaOsuEQ7w9 +vMYcdtRq8TsjA2JImbSI0TIg8gb2FQxPcYwTJKl+FICOeIwtaSg5hTtJZpnxX5LO +utTaC0DZjNkTk5RdOdWA8tihyUdGqKoxJY2TVmwGe2rUEDjFB++J4inkEwKBgB6V +g0nmtkxanFrzOzFlMXwgEEHF+Xaqb9QFNa/xs6XeNnREAapO7JV75Cr6H2hFMFe1 +mJjyqCgYUoCWX3iaHtLJRnEkBtNY4kzyQB6m46LtsnnnXO/dwKA2oDyoPfFNRoDq +YatEd3JIXNU9s2T/+x7WdOBjKhh72dTkbPFmTPDdAoGAU6rlPBevqOFdObYxdPq8 +EQWu44xqky3Mf5sBpOwtu6rqCYuziLiN7K4sjN5GD5mb1cEU+oS92ZiNcUQ7MFXk +8yTYZ7U0VcXyAcpYreWwE8thmb0BohJBr+Mp3wLTx32x0HKdO6vpUa0d35LUTUmM +RrKmPK/msHKK/sVHiL+NFqo= +-----END PRIVATE KEY----- diff --git a/test/cypress/fixtures/test.example.com.pem b/test/cypress/fixtures/test.example.com.pem new file mode 100644 index 000000000..16340cdfd --- /dev/null +++ b/test/cypress/fixtures/test.example.com.pem @@ -0,0 +1,26 @@ +-----BEGIN CERTIFICATE----- +MIIEYDCCAsigAwIBAgIRAPoSC0hvitb26ODMlsH6YbowDQYJKoZIhvcNAQELBQAw +gZExHjAcBgNVBAoTFW1rY2VydCBkZXZlbG9wbWVudCBDQTEzMDEGA1UECwwqamN1 +cm5vd0BKYW1pZXMtTGFwdG9wLmxvY2FsIChKYW1pZSBDdXJub3cpMTowOAYDVQQD +DDFta2NlcnQgamN1cm5vd0BKYW1pZXMtTGFwdG9wLmxvY2FsIChKYW1pZSBDdXJu +b3cpMB4XDTI0MTAwOTA3MjIxN1oXDTI3MDEwOTA3MjIxN1owXjEnMCUGA1UEChMe +bWtjZXJ0IGRldmVsb3BtZW50IGNlcnRpZmljYXRlMTMwMQYDVQQLDCpqY3Vybm93 +QEphbWllcy1MYXB0b3AubG9jYWwgKEphbWllIEN1cm5vdykwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQC1n9j9C5Bes1ndqACDckERauxXVNKCnUlUM1bu +GBx1xc+j2e2Ar23wUJJuWBY18VfT8yqfqVDktO2wrbmvZvLuPmXePOKbIKS+XXh+ +2NG9L5bDG9rwGFCRXnbQj+GWCdMfzx14+CR1IHgeYz6Cv/Si2/LJPCh/CoBfM4hU +QJON3lxAWrWBpdbZnKYMrxuPBRfW9OuzTbCVXToQoxRAHiOR9081Xn1WeoKr7kVB +Ia5UphlvWXa12w1YmUwJu7YndnJGIavLWeNCVc7ZEo+nS8Wr/4QWicatIWZXpVaE +OPhRoeplQDxNWg5b/Q26rYoVd7PrCmRs7sVcH79XzGONeH1PAgMBAAGjZTBjMA4G +A1UdDwEB/wQEAwIFoDATBgNVHSUEDDAKBggrBgEFBQcDATAfBgNVHSMEGDAWgBSB +/vfmBUd4W7CvyEMl7YpMVQs8vTAbBgNVHREEFDASghB0ZXN0LmV4YW1wbGUuY29t +MA0GCSqGSIb3DQEBCwUAA4IBgQASwON/jPAHzcARSenY0ZGY1m5OVTYoQ/JWH0oy +l8SyFCQFEXt7UHDD/eTtLT0vMyc190nP57P8lTnZGf7hSinZz1B1d6V4cmzxpk0s +VXZT+irL6bJVJoMBHRpllKAhGULIo33baTrWFKA0oBuWx4AevSWKcLW5j87kEawn +ATCuMQ1I3ifR1mSlB7X8fb+vF+571q0NGuB3a42j6rdtXJ6SmH4+9B4qO0sfHDNt +IImpLCH/tycDpcYrGSCn1QrekFG1bSEh+Bb9i8rqMDSDsYrTFPZTuOQ3EtjGni9u +m+rEP3OyJg+md8c+0LVP7/UU4QWWnw3/Wolo5kSCxE8vNTFqi4GhVbdLnUtcIdTV +XxuR6cKyW87Snj1a0nG76ZLclt/akxDhtzqeV60BO0p8pmiev8frp+E94wFNYCmp +1cr3CnMEGRaficLSDFC6EBENzlZW2BQT6OMIV+g0NBgSyQe39s2zcdEl5+SzDVuw +hp8bJUp/QN7pnOVCDbjTQ+HVMXw= +-----END CERTIFICATE----- diff --git a/test/cypress/plugins/backendApi/client.js b/test/cypress/plugins/backendApi/client.js index 29684cfdc..e7c0c439d 100644 --- a/test/cypress/plugins/backendApi/client.js +++ b/test/cypress/plugins/backendApi/client.js @@ -1,9 +1,14 @@ const logger = require('./logger'); -const restler = require('@jc21/restler'); +const axios = require('axios').default; const BackendApi = function(config, token) { this.config = config; this.token = token; + + this.axios = axios.create({ + baseURL: config.baseUrl, + timeout: 5000, + }); }; /** @@ -14,128 +19,113 @@ BackendApi.prototype.setToken = function(token) { }; /** - * @param {string} path - * @param {bool} [returnOnError] - * @returns {Promise} + * @param {bool} returnOnError */ -BackendApi.prototype.get = function(path, returnOnError) { - return new Promise((resolve, reject) => { - let headers = { +BackendApi.prototype._prepareOptions = function(returnOnError) { + let options = { + headers: { Accept: 'application/json' - }; - if (this.token) { - headers.Authorization = 'Bearer ' + this.token; } - - logger('GET ', this.config.baseUrl + path); - - restler - .get(this.config.baseUrl + path, { - headers: headers, - }) - .on('complete', function(data, response) { - logger('Response data:', data); - if (!returnOnError && data instanceof Error) { - reject(data); - } else if (!returnOnError && response.statusCode != 200) { - if (typeof data === 'object' && typeof data.error === 'object' && typeof data.error.message !== 'undefined') { - reject(new Error(data.error.code + ': ' + data.error.message)); - } else { - reject(new Error('Error ' + response.statusCode)); - } - } else { - resolve(data); - } - }); - }); + } + if (this.token) { + options.headers.Authorization = 'Bearer ' + this.token; + } + if (returnOnError) { + options.validateStatus = function () { + return true; + } + } + return options; }; /** - * @param {string} path - * @param {bool} [returnOnError] - * @returns {Promise} + * @param {*} response + * @param {function} resolve + * @param {function} reject + * @param {bool} returnOnError */ -BackendApi.prototype.delete = function(path, returnOnError) { - return new Promise((resolve, reject) => { - let headers = { - Accept: 'application/json' - }; - if (this.token) { - headers.Authorization = 'Bearer ' + this.token; +BackendApi.prototype._handleResponse = function(response, resolve, reject, returnOnError) { + logger('Response data:', response.data); + if (!returnOnError && typeof response.data === 'object' && typeof response.data.error === 'object') { + if (typeof response.data === 'object' && typeof response.data.error === 'object' && typeof response.data.error.message !== 'undefined') { + reject(new Error(response.data.error.code + ': ' + response.data.error.message)); + } else { + reject(new Error('Error ' + response.status)); } - - logger('DELETE ', this.config.baseUrl + path); - - restler - .del(this.config.baseUrl + path, { - headers: headers, - }) - .on('complete', function(data, response) { - logger('Response data:', data); - if (!returnOnError && data instanceof Error) { - reject(data); - } else if (!returnOnError && response.statusCode != 200) { - if (typeof data === 'object' && typeof data.error === 'object' && typeof data.error.message !== 'undefined') { - reject(new Error(data.error.code + ': ' + data.error.message)); - } else { - reject(new Error('Error ' + response.statusCode)); - } - } else { - resolve(data); - } - }); - }); + } else { + resolve(response.data); + } }; /** - * @param {string} path - * @param {object} data - * @param {bool} [returnOnError] - * @returns {Promise} + * @param {*} err + * @param {function} resolve + * @param {function} reject + * @param {bool} returnOnError */ -BackendApi.prototype.postJson = function(path, data, returnOnError) { - logger('POST ', this.config.baseUrl + path); - return this._putPostJson('postJson', path, data, returnOnError); +BackendApi.prototype._handleError = function(err, resolve, reject, returnOnError) { + logger('Axios Error:', err); + if (returnOnError) { + resolve(typeof err.response.data !== 'undefined' ? err.response.data : err); + } else { + reject(err); + } }; /** + * @param {string} method * @param {string} path - * @param {object} data * @param {bool} [returnOnError] + * @param {*} [data] * @returns {Promise} */ -BackendApi.prototype.putJson = function(path, data, returnOnError) { - logger('PUT ', this.config.baseUrl + path); - return this._putPostJson('putJson', path, data, returnOnError); +BackendApi.prototype.request = function (method, path, returnOnError, data) { + logger(method.toUpperCase(), this.config.baseUrl + path); + const options = this._prepareOptions(returnOnError); + + return new Promise((resolve, reject) => { + let opts = { + method: method, + url: path, + ...options + } + if (data !== undefined && data !== null) { + opts.data = data; + } + + this.axios(opts) + .then((response) => { + this._handleResponse(response, resolve, reject, returnOnError); + }) + .catch((err) => { + this._handleError(err, resolve, reject, returnOnError); + }); + }); }; /** * @param {string} path - * @param {object} data + * @param {form} form * @param {bool} [returnOnError] * @returns {Promise} */ -BackendApi.prototype._putPostJson = function(fn, path, data, returnOnError) { +BackendApi.prototype.postForm = function (path, form, returnOnError) { + logger('POST', this.config.baseUrl + path); + const options = this._prepareOptions(returnOnError); + return new Promise((resolve, reject) => { - restler[fn](this.config.baseUrl + path, data, { - headers: { - Accept: 'application/json', - Authorization: 'Bearer ' + this.token, - }, - }).on('complete', function(data, response) { - logger('Response data:', data); - if (!returnOnError && data instanceof Error) { - reject(data); - } else if (!returnOnError && (response.statusCode < 200 || response.statusCode >= 300)) { - if (typeof data === 'object' && typeof data.error === 'object' && typeof data.error.message !== 'undefined') { - reject(new Error(data.error.code + ': ' + data.error.message)); - } else { - reject(new Error('Error ' + response.statusCode)); - } - } else { - resolve(data); - } - }); + const opts = { + ...options, + ...form.getHeaders(), + } + + this.axios.post(path, form, opts) + .then((response) => { + this._handleResponse(response, resolve, reject, returnOnError); + }) + .catch((err) => { + this._handleError(err, resolve, reject, returnOnError); + }); }); }; diff --git a/test/cypress/plugins/backendApi/task.js b/test/cypress/plugins/backendApi/task.js index 2f67902d5..ab9704f4a 100644 --- a/test/cypress/plugins/backendApi/task.js +++ b/test/cypress/plugins/backendApi/task.js @@ -1,8 +1,9 @@ +const fs = require('fs'); +const FormData = require('form-data'); const logger = require('./logger'); const Client = require('./client'); module.exports = function (config) { - logger('Client Ready using', config.baseUrl); return { @@ -17,7 +18,7 @@ module.exports = function (config) { backendApiGet: (options) => { const api = new Client(config); api.setToken(options.token); - return api.get(options.path, options.returnOnError || false); + return api.request('get', options.path, options.returnOnError || false); }, /** @@ -31,7 +32,26 @@ module.exports = function (config) { backendApiPost: (options) => { const api = new Client(config); api.setToken(options.token); - return api.postJson(options.path, options.data, options.returnOnError || false); + return api.request('post', options.path, options.returnOnError || false, options.data); + }, + + /** + * @param {object} options + * @param {string} options.token JWT + * @param {string} options.path API path + * @param {object} options.files + * @param {bool} [options.returnOnError] If true, will return instead of throwing errors + * @returns {string} + */ + backendApiPostFiles: (options) => { + const api = new Client(config); + api.setToken(options.token); + + const form = new FormData(); + for (let [key, value] of Object.entries(options.files)) { + form.append(key, fs.createReadStream(config.fixturesFolder + '/' + value)); + } + return api.postForm(options.path, form, options.returnOnError || false); }, /** @@ -45,7 +65,7 @@ module.exports = function (config) { backendApiPut: (options) => { const api = new Client(config); api.setToken(options.token); - return api.putJson(options.path, options.data, options.returnOnError || false); + return api.request('put', options.path, options.returnOnError || false, options.data); }, /** @@ -58,7 +78,7 @@ module.exports = function (config) { backendApiDelete: (options) => { const api = new Client(config); api.setToken(options.token); - return api.delete(options.path, options.returnOnError || false); + return api.request('delete', options.path, options.returnOnError || false); } }; -}; \ No newline at end of file +}; diff --git a/test/package.json b/test/package.json index 69b2b8613..7032efe68 100644 --- a/test/package.json +++ b/test/package.json @@ -1,11 +1,11 @@ { - "name": "test", + "name": "npm-test", "version": "1.0.0", "description": "", "main": "index.js", "dependencies": { - "@jc21/cypress-swagger-validation": "^0.2.6", - "@jc21/restler": "^3.4.0", + "@jc21/cypress-swagger-validation": "^0.2.7", + "axios": "^1.7.7", "cypress": "^13.15.0", "cypress-multi-reporters": "^1.6.4", "cypress-wait-until": "^3.0.2", @@ -13,6 +13,7 @@ "eslint-plugin-align-assignments": "^1.1.2", "eslint-plugin-chai-friendly": "^1.0.1", "eslint-plugin-cypress": "^3.5.0", + "form-data": "^4.0.1", "lodash": "^4.17.21", "mocha": "^10.7.3", "mocha-junit-reporter": "^2.2.1" diff --git a/test/yarn.lock b/test/yarn.lock index b34385bd2..e831b1054 100644 --- a/test/yarn.lock +++ b/test/yarn.lock @@ -167,29 +167,19 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.3.1.tgz#c72a5c76a9fbaf3488e231b13dc52c0da7bab42a" integrity sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA== -"@jc21/cypress-swagger-validation@^0.2.6": - version "0.2.6" - resolved "https://registry.yarnpkg.com/@jc21/cypress-swagger-validation/-/cypress-swagger-validation-0.2.6.tgz#8b61f2413fa81cae6f8c2f33ecce5a6ded897030" - integrity sha512-8i8poTwi13e4BRKWpvmXFmqvEfQq3Kn9tunWhNYT7IQwiMeUVou+g1yh99QzuI501DBPtL2XEwjNukxTf5GiyQ== +"@jc21/cypress-swagger-validation@^0.2.7": + version "0.2.7" + resolved "https://registry.yarnpkg.com/@jc21/cypress-swagger-validation/-/cypress-swagger-validation-0.2.7.tgz#64642b12d98b884df8c30b72852162941285d2af" + integrity sha512-4EQ0gfigRwVVl3DnVYbR48/EKGnn7oH5YYdMzf6zqypO+bqYvDHu9kgk/WqkGlT/aauGQ7e0YGMo8ZvR7mL0Ng== dependencies: "@apidevtools/swagger-parser" "^10.1.0" - ajv "^8.12.0" + ajv "^8.17.1" json-schema "^0.4.0" - json-schema-ref-parser "^9.0.6" + json-schema-ref-parser "^9.0.9" jsonpath "^1.1.1" lodash "^4.17.21" openapi-types "^12.1.3" - picocolors "^1.0.0" - -"@jc21/restler@^3.4.0": - version "3.4.0" - resolved "https://registry.yarnpkg.com/@jc21/restler/-/restler-3.4.0.tgz#cfa214ddb9946a800c6fe472529f72b01e93c763" - integrity sha512-P1Nl2ifoQwqtxcqJKYHvxgPfckeIZWbVSYMlNAP+cL2KNk3U5eErPKt4xr5YLIQ+NarFsHMGH8+CBa00FKAGrw== - dependencies: - iconv-lite "0.2.11" - qs "1.2.0" - xml2js "0.4.0" - yaml "0.2.3" + picocolors "^1.1.0" "@jsdevtools/ono@^7.1.3": version "7.1.3" @@ -271,7 +261,17 @@ ajv@^6.12.4: json-schema-traverse "^0.4.1" uri-js "^4.2.2" -ajv@^8.12.0, ajv@^8.6.3: +ajv@^8.17.1: + version "8.17.1" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.17.1.tgz#37d9a5c776af6bc92d7f4f9510eba4c0a60d11a6" + integrity sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g== + dependencies: + fast-deep-equal "^3.1.3" + fast-uri "^3.0.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + +ajv@^8.6.3: version "8.13.0" resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.13.0.tgz#a3939eaec9fb80d217ddf0c3376948c023f28c91" integrity sha512-PRA911Blj99jR5RMeTunVbNXMF6Lp4vZXnk5GQjcnUWUTsrXtekg/pnmFFI2u/I36Y/2bITGS30GZCXei6uNkA== @@ -390,6 +390,15 @@ aws4@^1.8.0: resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.9.0.tgz#24390e6ad61386b0a747265754d2a17219de862c" integrity sha512-Uvq6hVe90D0B2WEnUqtdgY1bATGz3mw33nH9Y+dmA+w5DHvUmBgkr5rM/KCHpCsiFNRUfokW/szpPPgMK2hm4A== +axios@^1.7.7: + version "1.7.7" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.7.tgz#2f554296f9892a72ac8d8e4c5b79c14a91d0a47f" + integrity sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q== + dependencies: + follow-redirects "^1.15.6" + form-data "^4.0.0" + proxy-from-env "^1.1.0" + balanced-match@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" @@ -506,11 +515,6 @@ chalk@^4.0.0, chalk@^4.1.0: ansi-styles "^4.1.0" supports-color "^7.1.0" -chalk@^5.3.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.3.0.tgz#67c20a7ebef70e7f3970a01f90fa210cb6860385" - integrity sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w== - charenc@0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667" @@ -1049,6 +1053,11 @@ fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6: resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= +fast-uri@^3.0.1: + version "3.0.2" + resolved "https://registry.yarnpkg.com/fast-uri/-/fast-uri-3.0.2.tgz#d78b298cf70fd3b752fd951175a3da6a7b48f024" + integrity sha512-GR6f0hD7XXyNJa25Tb9BuIdN0tdr+0BMi6/CJPH3wJO1JjNG3n/VsSw38AwRdKZABm8lGbPfakLRkYzx2V9row== + fd-slicer@~1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e" @@ -1103,11 +1112,25 @@ flatted@^3.2.9: resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.1.tgz#21db470729a6734d4997002f439cb308987f567a" integrity sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw== +follow-redirects@^1.15.6: + version "1.15.9" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.9.tgz#a604fa10e443bf98ca94228d9eebcc2e8a2c8ee1" + integrity sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ== + forever-agent@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= +form-data@^4.0.0, form-data@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.1.tgz#ba1076daaaa5bfd7e99c1a6cb02aa0a5cff90d48" + integrity sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + form-data@~4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" @@ -1283,11 +1306,6 @@ human-signals@^1.1.1: resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw== -iconv-lite@0.2.11: - version "0.2.11" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.2.11.tgz#1ce60a3a57864a292d1321ff4609ca4bb965adc8" - integrity sha1-HOYKOleGSiktEyH/RgnKS7llrcg= - ieee754@^1.1.13: version "1.2.1" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" @@ -1450,7 +1468,7 @@ json-buffer@3.0.1: resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== -json-schema-ref-parser@^9.0.6: +json-schema-ref-parser@^9.0.9: version "9.0.9" resolved "https://registry.yarnpkg.com/json-schema-ref-parser/-/json-schema-ref-parser-9.0.9.tgz#66ea538e7450b12af342fa3d5b8458bc1e1e013f" integrity sha512-qcP2lmGy+JUoQJ4DOQeLaZDqH9qSkeGCK3suKWxJXS82dg728Mn3j97azDMaOUmJAN4uCq91LdPx4K7E8F1a7Q== @@ -1812,10 +1830,10 @@ performance-now@^2.1.0: resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= -picocolors@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.1.tgz#a8ad579b571952f0e5d25892de5445bcfe25aaa1" - integrity sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew== +picocolors@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.0.tgz#5358b76a78cde483ba5cef6a9dc9671440b27d59" + integrity sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw== picomatch@^2.0.4: version "2.2.2" @@ -1857,6 +1875,11 @@ proxy-from-env@1.0.0: resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.0.0.tgz#33c50398f70ea7eb96d21f7b817630a55791c7ee" integrity sha512-F2JHgJQ1iqwnHDcQjVBsq3n/uoaFL+iPW/eAeL7kVxy/2RrWaN4WroKjjvbsoRtv0ftelNyC01bjRhn/bhcf4A== +proxy-from-env@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" + integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== + psl@^1.1.33: version "1.9.0" resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7" @@ -1875,11 +1898,6 @@ punycode@^2.1.0, punycode@^2.1.1: resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== -qs@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-1.2.0.tgz#ed079be28682147e6fd9a34cc2b0c1e0ec6453ee" - integrity sha1-7Qeb4oaCFH5v2aNMwrDB4OxkU+4= - qs@6.13.0: version "6.13.0" resolved "https://registry.yarnpkg.com/qs/-/qs-6.13.0.tgz#6ca3bd58439f7e245655798997787b0d88a51906" @@ -1968,11 +1986,6 @@ safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== -sax@0.5.x: - version "0.5.8" - resolved "https://registry.yarnpkg.com/sax/-/sax-0.5.8.tgz#d472db228eb331c2506b0e8c15524adb939d12c1" - integrity sha1-1HLbIo6zMcJQaw6MFVJK25OdEsE= - semver@^7.5.3: version "7.6.2" resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.2.tgz#1e3b34759f896e8f14d6134732ce798aeb0c6e13" @@ -2309,34 +2322,16 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= -xml2js@0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.0.tgz#124fc4114b4129c810800ecb2ac86cf25462cb9a" - integrity sha1-Ek/EEUtBKcgQgA7LKshs8lRiy5o= - dependencies: - sax "0.5.x" - xmlbuilder ">=0.4.2" - xml@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/xml/-/xml-1.0.1.tgz#78ba72020029c5bc87b8a81a3cfcd74b4a2fc1e5" integrity sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw== -xmlbuilder@>=0.4.2: - version "13.0.2" - resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-13.0.2.tgz#02ae33614b6a047d1c32b5389c1fdacb2bce47a7" - integrity sha512-Eux0i2QdDYKbdbA6AM6xE4m6ZTZr4G4xF9kahI2ukSEMCzwce2eX9WlTI5J3s+NU7hpasFsr8hWIONae7LluAQ== - y18n@^5.0.5: version "5.0.8" resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== -yaml@0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/yaml/-/yaml-0.2.3.tgz#b5450e92e76ef36b5dd24e3660091ebaeef3e5c7" - integrity sha1-tUUOkudu82td0k42YAkeuu7z5cc= - yargs-parser@^20.2.2, yargs-parser@^20.2.9: version "20.2.9" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" From d21403ca1e08af90069222f7513b490719295190 Mon Sep 17 00:00:00 2001 From: Jamie Curnow Date: Fri, 11 Oct 2024 12:56:29 +1000 Subject: [PATCH 5/5] Move docker login in pipeline --- Jenkinsfile | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 1d8680a6b..ae631f935 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -56,6 +56,13 @@ pipeline { sh 'sed -i -E "s/(version-)[0-9]+\\.[0-9]+\\.[0-9]+(-green)/\\1${BUILD_VERSION}\\2/" README.md' } } + stage('Docker Login') { + steps { + withCredentials([usernamePassword(credentialsId: 'jc21-dockerhub', passwordVariable: 'dpass', usernameVariable: 'duser')]) { + sh 'docker login -u "${duser}" -p "${dpass}"' + } + } + } } } stage('Builds') { @@ -157,10 +164,7 @@ pipeline { } } steps { - withCredentials([usernamePassword(credentialsId: 'jc21-dockerhub', passwordVariable: 'dpass', usernameVariable: 'duser')]) { - sh 'docker login -u "${duser}" -p "${dpass}"' - sh "./scripts/buildx --push ${buildxPushTags}" - } + sh "./scripts/buildx --push ${buildxPushTags}" } } stage('Docs / Comment') {