diff --git a/Dockerfile b/Dockerfile index 90084cef..2301fd71 100644 --- a/Dockerfile +++ b/Dockerfile @@ -70,7 +70,7 @@ RUN apk upgrade --no-cache -a && \ FROM zoeyvid/nginx-quic:347-python SHELL ["/bin/ash", "-eo", "pipefail", "-c"] COPY rootfs / -COPY --from=zoeyvid/certbot-docker:53 /usr/local /usr/local +COPY --from=zoeyvid/certbot-docker:58 /usr/local /usr/local COPY --from=zoeyvid/curl-quic:419 /usr/local/bin/curl /usr/local/bin/curl ARG CRS_VER=v4.7.0 diff --git a/backend/internal/nginx.js b/backend/internal/nginx.js index 76844851..a81c7931 100644 --- a/backend/internal/nginx.js +++ b/backend/internal/nginx.js @@ -97,7 +97,7 @@ const internalNginx = { reload: () => { return internalNginx.test().then(() => { try { - utils.exec('certbot-ocsp-fetcher.sh -c /data/tls/certbot -o /data/tls/certbot/live --quiet --no-reload-webserver || true'); + utils.exec('certbot-ocsp-fetcher.sh -c /data/tls/certbot -o /data/tls/certbot/live --no-reload-webserver --quiet || true'); } catch { // do nothing } diff --git a/backend/lib/express/cors.js b/backend/lib/express/cors.js index 895f620f..2b33c420 100644 --- a/backend/lib/express/cors.js +++ b/backend/lib/express/cors.js @@ -3,7 +3,7 @@ module.exports = function (req, res, 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-Methods': 'OPTIONS, GET, POST, PUT', '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', diff --git a/backend/package.json b/backend/package.json index 4b6b9236..4b8335f3 100644 --- a/backend/package.json +++ b/backend/package.json @@ -30,12 +30,11 @@ "license": "MIT", "devDependencies": { "@apidevtools/swagger-parser": "10.1.0", - "chalk": "4.1.2", + "@eslint/js": "9.12.0", "eslint": "9.12.0", "eslint-config-prettier": "9.1.0", "eslint-plugin-prettier": "5.2.1", "globals": "15.11.0", - "nodemon": "2.0.22", "prettier": "3.3.3" }, "scripts": { diff --git a/backend/routes/nginx/certificates.js b/backend/routes/nginx/certificates.js index b69eaba7..ac461367 100644 --- a/backend/routes/nginx/certificates.js +++ b/backend/routes/nginx/certificates.js @@ -198,7 +198,7 @@ router }); /** - * Renew LE Certs + * Renew certbot Certs * * /api/nginx/certificates/123/renew */ @@ -227,7 +227,7 @@ router }); /** - * Download LE Certs + * Download certbot Certs * * /api/nginx/certificates/123/download */ diff --git a/backend/schema/common.json b/backend/schema/common.json index 83de0143..c3e6316b 100644 --- a/backend/schema/common.json +++ b/backend/schema/common.json @@ -72,7 +72,7 @@ "description": "Domain Names separated by a comma", "type": "array", "minItems": 1, - "maxItems": 100, + "maxItems": 99, "uniqueItems": true, "items": { "type": "string", diff --git a/backend/schema/components/stream-object.json b/backend/schema/components/stream-object.json index 516c7f89..70d9bbf0 100644 --- a/backend/schema/components/stream-object.json +++ b/backend/schema/components/stream-object.json @@ -17,9 +17,9 @@ "$ref": "../common.json#/properties/user_id" }, "incoming_port": { - "type": "integer", - "minimum": 1, - "maximum": 65535 + "type": "string", + "pattern": "^([0-9]+|[0-9]+-[0-9]+)$", + "maxLength": 11 }, "forwarding_host": { "anyOf": [ diff --git a/backend/schema/index.js b/backend/schema/index.js index 87b75f25..2139a618 100644 --- a/backend/schema/index.js +++ b/backend/schema/index.js @@ -3,7 +3,6 @@ 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 @@ -26,16 +25,9 @@ module.exports = { * @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' - ) { + 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/paths/users/userID/auth/put.json b/backend/schema/paths/users/userID/auth/put.json index a72f5617..9e3e269d 100644 --- a/backend/schema/paths/users/userID/auth/put.json +++ b/backend/schema/paths/users/userID/auth/put.json @@ -45,13 +45,13 @@ "current": { "type": "string", "minLength": 1, - "maxLength": 64, + "maxLength": 99, "example": "changeme" }, "secret": { "type": "string", "minLength": 8, - "maxLength": 64, + "maxLength": 99, "example": "mySuperN3wP@ssword!" } } diff --git a/backend/schema/swagger.json b/backend/schema/swagger.json index 5a0142bf..4a88e100 100644 --- a/backend/schema/swagger.json +++ b/backend/schema/swagger.json @@ -1,7 +1,7 @@ { "openapi": "3.1.0", "info": { - "title": "Nginx Proxy Manager API", + "title": "NPMplus API", "version": "2.x.x" }, "servers": [ diff --git a/backend/validate-schema.js b/backend/validate-schema.js index 71a05c81..e3638594 100644 --- a/backend/validate-schema.js +++ b/backend/validate-schema.js @@ -1,16 +1,15 @@ const SwaggerParser = require('@apidevtools/swagger-parser'); -const chalk = require('chalk'); -const schema = require('./schema'); -const log = console.log; +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')); + log('❯ Schema is valid'); } catch (e) { console.error(e); - log(chalk.red('❯', e.message), '\n'); + log('❯', e.message, '\n'); process.exit(1); } }); diff --git a/rootfs/usr/local/bin/start.sh b/rootfs/usr/local/bin/start.sh index b4612d35..2bfc4c86 100755 --- a/rootfs/usr/local/bin/start.sh +++ b/rootfs/usr/local/bin/start.sh @@ -587,8 +587,9 @@ find /data/nginx -type f -name '*.conf' -not -path "/data/nginx/custom/*" -exec find /data/nginx -type f -name '*.conf' -not -path "/data/nginx/custom/*" -exec sed -i "/ssl_stapling/d" {} \; find /data/nginx -type f -name '*.conf' -not -path "/data/nginx/custom/*" -exec sed -i "/ssl_stapling_verify/d" {} \; -sed -i "/ssl_stapling/d" /data/nginx/default.conf -sed -i "/ssl_stapling_verify/d" /data/nginx/default.conf + +if [ -s /data/nginx/default.conf ]; then sed -i "/ssl_stapling/d" /data/nginx/default.conf; fi +if [ -s /data/nginx/default.conf ]; then sed -i "/ssl_stapling_verify/d" /data/nginx/default.conf; fi if [ ! -s /data/etc/modsecurity/modsecurity-default.conf ]; then cp -van /usr/local/nginx/conf/conf.d/include/modsecurity.conf.example /data/etc/modsecurity/modsecurity-default.conf @@ -981,7 +982,7 @@ if [ "$PUID" != "0" ]; then sed -i "s|user =.*|;user = root|" /data/php/83/php-fpm.d/www.conf sed -i "s|group =.*|;group = root|" /data/php/83/php-fpm.d/www.conf fi - sed -i "s|user root;|#user root;|g" /usr/local/nginx/conf/nginx.conf + sed -i "s|#\?user root;|#user root;|g" /usr/local/nginx/conf/nginx.conf exec su-exec "$PUID:$PGID" launch.sh else find /proc/self/fd \ diff --git a/rootfs/usr/local/nginx/conf/conf.d/include/always.conf b/rootfs/usr/local/nginx/conf/conf.d/include/always.conf index f8cd08a9..53d0c341 100644 --- a/rootfs/usr/local/nginx/conf/conf.d/include/always.conf +++ b/rootfs/usr/local/nginx/conf/conf.d/include/always.conf @@ -16,6 +16,8 @@ location = /fancyindex { location /fancyindex/ { alias /html/fancyindex/; + fancyindex off; + index off; } diff --git a/rootfs/usr/local/nginx/conf/conf.d/include/proxy-location.conf b/rootfs/usr/local/nginx/conf/conf.d/include/proxy-location.conf index b99cccf3..6cc16ebe 100644 --- a/rootfs/usr/local/nginx/conf/conf.d/include/proxy-location.conf +++ b/rootfs/usr/local/nginx/conf/conf.d/include/proxy-location.conf @@ -3,7 +3,7 @@ proxy_set_header X-Forwarded-Port $server_port; proxy_set_header X-Forwarded-Scheme $scheme; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Real-IP $remote_addr; -proxy_set_header Accept-Encoding ""; +#proxy_set_header Accept-Encoding ""; proxy_set_header Host $host; proxy_set_header Early-Data $ssl_early_data; diff --git a/rootfs/usr/local/nginx/conf/conf.d/include/proxy.conf b/rootfs/usr/local/nginx/conf/conf.d/include/proxy.conf index e0bbaf86..42b694d7 100644 --- a/rootfs/usr/local/nginx/conf/conf.d/include/proxy.conf +++ b/rootfs/usr/local/nginx/conf/conf.d/include/proxy.conf @@ -3,7 +3,7 @@ proxy_set_header X-Forwarded-Port $server_port; proxy_set_header X-Forwarded-Scheme $scheme; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Real-IP $remote_addr; -proxy_set_header Accept-Encoding ""; +#proxy_set_header Accept-Encoding ""; proxy_set_header Host $host; proxy_set_header Early-Data $ssl_early_data; diff --git a/rootfs/usr/local/nginx/conf/nginx.conf b/rootfs/usr/local/nginx/conf/nginx.conf index 28ae14d5..3184a6d0 100644 --- a/rootfs/usr/local/nginx/conf/nginx.conf +++ b/rootfs/usr/local/nginx/conf/nginx.conf @@ -36,6 +36,7 @@ http { tcp_nodelay on; client_max_body_size 0; client_body_buffer_size 512k; + reset_timedout_connection on; gzip on; gzip_vary on; diff --git a/test/cypress/e2e/api/Certificates.cy.js b/test/cypress/e2e/api/Certificates.cy.js deleted file mode 100644 index 043680f3..00000000 --- a/test/cypress/e2e/api/Certificates.cy.js +++ /dev/null @@ -1,50 +0,0 @@ -/// - -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 deleted file mode 100644 index 307cdc30..00000000 --- a/test/cypress/fixtures/test.example.com-key.pem +++ /dev/null @@ -1,28 +0,0 @@ ------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 deleted file mode 100644 index 16340cdf..00000000 --- a/test/cypress/fixtures/test.example.com.pem +++ /dev/null @@ -1,26 +0,0 @@ ------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-----