diff --git a/.version b/.version index 56beced9..dcb27a75 100644 --- a/.version +++ b/.version @@ -1 +1 @@ -2.12.4 +2.12.5 diff --git a/Jenkinsfile b/Jenkinsfile index 66ed7cb6..af913c2e 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -241,12 +241,17 @@ pipeline { } steps { script { - npmGithubPrComment("""Docker Image for build ${BUILD_NUMBER} is available on -[DockerHub](https://cloud.docker.com/repository/docker/nginxproxymanager/${IMAGE}-dev) -as `nginxproxymanager/${IMAGE}-dev:${BRANCH_LOWER}` + npmGithubPrComment("""Docker Image for build ${BUILD_NUMBER} is available on [DockerHub](https://cloud.docker.com/repository/docker/nginxproxymanager/${IMAGE}-dev): +``` +nginxproxymanager/${IMAGE}-dev:${BRANCH_LOWER} +``` -**Note:** ensure you backup your NPM instance before testing this image! Especially if there are database changes -**Note:** this is a different docker image namespace than the official image +> [!NOTE] +> Ensure you backup your NPM instance before testing this image! Especially if there are database changes. +> This is a different docker image namespace than the official image. + +> [!WARNING] +> Changes and additions to DNS Providers require verification by at least 2 members of the community! """, true) } } diff --git a/README.md b/README.md index 905e83cf..3f7c2178 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@



- + diff --git a/backend/lib/certbot.js b/backend/lib/certbot.js index eb1966dc..96d94710 100644 --- a/backend/lib/certbot.js +++ b/backend/lib/certbot.js @@ -11,7 +11,7 @@ const certbot = { /** * @param {array} pluginKeys */ - installPlugins: async function (pluginKeys) { + installPlugins: async (pluginKeys) => { let hasErrors = false; return new Promise((resolve, reject) => { @@ -21,7 +21,7 @@ const certbot = { } batchflow(pluginKeys).sequential() - .each((i, pluginKey, next) => { + .each((_i, pluginKey, next) => { certbot.installPlugin(pluginKey) .then(() => { next(); @@ -51,7 +51,7 @@ const certbot = { * @param {string} pluginKey * @returns {Object} */ - installPlugin: async function (pluginKey) { + installPlugin: async (pluginKey) => { if (typeof dnsPlugins[pluginKey] === 'undefined') { // throw Error(`Certbot plugin ${pluginKey} not found`); throw new error.ItemNotFoundError(pluginKey); @@ -63,8 +63,15 @@ const certbot = { plugin.version = plugin.version.replace(/{{certbot-version}}/g, CERTBOT_VERSION_REPLACEMENT); plugin.dependencies = plugin.dependencies.replace(/{{certbot-version}}/g, CERTBOT_VERSION_REPLACEMENT); - const cmd = '. /opt/certbot/bin/activate && pip install --no-cache-dir ' + plugin.dependencies + ' ' + plugin.package_name + plugin.version + ' ' + ' && deactivate'; - return utils.exec(cmd) + // SETUPTOOLS_USE_DISTUTILS is required for certbot plugins to install correctly + // in new versions of Python + let env = Object.assign({}, process.env, {SETUPTOOLS_USE_DISTUTILS: 'stdlib'}); + if (typeof plugin.env === 'object') { + env = Object.assign(env, plugin.env); + } + + const cmd = `. /opt/certbot/bin/activate && pip install --no-cache-dir ${plugin.dependencies} ${plugin.package_name}${plugin.version} && deactivate`; + return utils.exec(cmd, {env}) .then((result) => { logger.complete(`Installed ${pluginKey}`); return result; diff --git a/backend/lib/utils.js b/backend/lib/utils.js index bcdb3341..66f2dfd9 100644 --- a/backend/lib/utils.js +++ b/backend/lib/utils.js @@ -1,13 +1,13 @@ const _ = require('lodash'); -const exec = require('child_process').exec; -const execFile = require('child_process').execFile; +const exec = require('node:child_process').exec; +const execFile = require('node:child_process').execFile; const { Liquid } = require('liquidjs'); const logger = require('../logger').global; const error = require('./error'); module.exports = { - exec: async function(cmd, options = {}) { + exec: async (cmd, options = {}) => { logger.debug('CMD:', cmd); const { stdout, stderr } = await new Promise((resolve, reject) => { @@ -31,11 +31,11 @@ module.exports = { * @param {Array} args * @returns {Promise} */ - execFile: function (cmd, args) { + execFile: (cmd, args) => { // logger.debug('CMD: ' + cmd + ' ' + (args ? args.join(' ') : '')); return new Promise((resolve, reject) => { - execFile(cmd, args, function (err, stdout, /*stderr*/) { + execFile(cmd, args, (err, stdout, /*stderr*/) => { if (err && typeof err === 'object') { reject(err); } else { @@ -51,7 +51,7 @@ module.exports = { * @param {Array} omissions * @returns {Function} */ - omitRow: function (omissions) { + omitRow: (omissions) => { /** * @param {Object} row * @returns {Object} @@ -67,7 +67,7 @@ module.exports = { * @param {Array} omissions * @returns {Function} */ - omitRows: function (omissions) { + omitRows: (omissions) => { /** * @param {Array} rows * @returns {Object} @@ -83,9 +83,9 @@ module.exports = { /** * @returns {Object} Liquid render engine */ - getRenderEngine: function () { + getRenderEngine: () => { const renderEngine = new Liquid({ - root: __dirname + '/../templates/' + root: `${__dirname}/../templates/` }); /** diff --git a/docker/rootfs/etc/s6-overlay/s6-rc.d/prepare/30-ownership.sh b/docker/rootfs/etc/s6-overlay/s6-rc.d/prepare/30-ownership.sh index 17bfa1a9..1ec117e1 100755 --- a/docker/rootfs/etc/s6-overlay/s6-rc.d/prepare/30-ownership.sh +++ b/docker/rootfs/etc/s6-overlay/s6-rc.d/prepare/30-ownership.sh @@ -27,15 +27,18 @@ chown -R "$PUID:$PGID" /etc/nginx/conf.d CERT_INIT_FLAG="/opt/certbot/.ownership_initialized" if [ ! -f "$CERT_INIT_FLAG" ]; then - # Prevents errors when installing python certbot plugins when non-root - chown "$PUID:$PGID" /opt/certbot /opt/certbot/bin + # Prevents errors when installing python certbot plugins when non-root + if [ "$SKIP_CERTBOT_OWNERSHIP" != "true" ]; then + log_info 'Changing ownership of /opt/certbot directories ...' + chown "$PUID:$PGID" /opt/certbot /opt/certbot/bin + fi - # Handle all site-packages directories efficiently - find /opt/certbot/lib -type d -name "site-packages" | while read -r SITE_PACKAGES_DIR; do - chown -R "$PUID:$PGID" "$SITE_PACKAGES_DIR" - done + # Handle all site-packages directories efficiently + find /opt/certbot/lib -type d -name "site-packages" | while read -r SITE_PACKAGES_DIR; do + chown -R "$PUID:$PGID" "$SITE_PACKAGES_DIR" + done - # Create a flag file to skip this step on subsequent runs - touch "$CERT_INIT_FLAG" - chown "$PUID:$PGID" "$CERT_INIT_FLAG" -fi \ No newline at end of file + # Create a flag file to skip this step on subsequent runs + touch "$CERT_INIT_FLAG" + chown "$PUID:$PGID" "$CERT_INIT_FLAG" +fi diff --git a/docker/scripts/install-s6 b/docker/scripts/install-s6 index 5f3b73ec..639c65dd 100755 --- a/docker/scripts/install-s6 +++ b/docker/scripts/install-s6 @@ -8,7 +8,7 @@ BLUE='\E[1;34m' GREEN='\E[1;32m' RESET='\E[0m' -S6_OVERLAY_VERSION=3.2.0.2 +S6_OVERLAY_VERSION=3.2.1.0 TARGETPLATFORM=${1:-linux/amd64} # Determine the correct binary file for the architecture given diff --git a/global/certbot-dns-plugins.json b/global/certbot-dns-plugins.json index 65e45f3a..9f878809 100644 --- a/global/certbot-dns-plugins.json +++ b/global/certbot-dns-plugins.json @@ -56,19 +56,19 @@ "full_plugin_name": "dns-bunny" }, "cdmon": { - "name": "cdmon", - "package_name": "certbot-dns-cdmon", - "version": "~=0.4.1", - "dependencies": "", - "credentials": "dns_cdmon_api_key=your-cdmon-api-token\ndns_cdmon_domain=your_domain_is_optional", - "full_plugin_name": "dns-cdmon" - }, + "name": "cdmon", + "package_name": "certbot-dns-cdmon", + "version": "~=0.4.1", + "dependencies": "", + "credentials": "dns_cdmon_api_key=your-cdmon-api-token\ndns_cdmon_domain=your_domain_is_optional", + "full_plugin_name": "dns-cdmon" + }, "cloudflare": { "name": "Cloudflare", "package_name": "certbot-dns-cloudflare", "version": "=={{certbot-version}}", - "dependencies": "cloudflare==4.0.* acme=={{certbot-version}}", - "credentials": "# Cloudflare API credentials used by Certbot\ndns_cloudflare_email = cloudflare@example.com\ndns_cloudflare_api_key = 0123456789abcdef0123456789abcdef01234", + "dependencies": "acme=={{certbot-version}}", + "credentials": "# Cloudflare API token\ndns_cloudflare_api_token=0123456789abcdef0123456789abcdef01234567", "full_plugin_name": "dns-cloudflare" }, "cloudns": { diff --git a/test/cypress/e2e/api/Certificates.cy.js b/test/cypress/e2e/api/Certificates.cy.js index 1e8a6fed..9f47edcb 100644 --- a/test/cypress/e2e/api/Certificates.cy.js +++ b/test/cypress/e2e/api/Certificates.cy.js @@ -10,7 +10,7 @@ describe('Certificates endpoints', () => { }); }); - it('Validate custom certificate', function() { + it('Validate custom certificate', () => { cy.task('backendApiPostFiles', { token: token, path: '/api/nginx/certificates/validate', @@ -25,7 +25,7 @@ describe('Certificates endpoints', () => { }); }); - it('Custom certificate lifecycle', function() { + it('Custom certificate lifecycle', () => { // Create custom cert cy.task('backendApiPost', { token: token, @@ -73,7 +73,7 @@ describe('Certificates endpoints', () => { }); }); - it('Request Certificate - CVE-2024-46256/CVE-2024-46257', function() { + it('Request Certificate - CVE-2024-46256/CVE-2024-46257', () => { cy.task('backendApiPost', { token: token, path: '/api/nginx/certificates', diff --git a/test/cypress/e2e/api/Dashboard.cy.js b/test/cypress/e2e/api/Dashboard.cy.js index 8fbb9715..62cb40e4 100644 --- a/test/cypress/e2e/api/Dashboard.cy.js +++ b/test/cypress/e2e/api/Dashboard.cy.js @@ -9,7 +9,7 @@ describe('Dashboard endpoints', () => { }); }); - it('Should be able to get host counts', function() { + it('Should be able to get host counts', () => { cy.task('backendApiGet', { token: token, path: '/api/reports/hosts' diff --git a/test/cypress/e2e/api/FullCertProvision.cy.js b/test/cypress/e2e/api/FullCertProvision.cy.js index 5ca5692c..9c6a7d2d 100644 --- a/test/cypress/e2e/api/FullCertProvision.cy.js +++ b/test/cypress/e2e/api/FullCertProvision.cy.js @@ -9,7 +9,7 @@ describe('Full Certificate Provisions', () => { }); }); - it('Should be able to create new http certificate', function() { + it('Should be able to create new http certificate', () => { cy.task('backendApiPost', { token: token, path: '/api/nginx/certificates', @@ -32,7 +32,7 @@ describe('Full Certificate Provisions', () => { }); }); - it('Should be able to create new DNS certificate with Powerdns', function() { + it('Should be able to create new DNS certificate with Powerdns', () => { cy.task('backendApiPost', { token: token, path: '/api/nginx/certificates', diff --git a/test/cypress/e2e/api/Health.cy.js b/test/cypress/e2e/api/Health.cy.js index 49881e97..d3e3306d 100644 --- a/test/cypress/e2e/api/Health.cy.js +++ b/test/cypress/e2e/api/Health.cy.js @@ -1,7 +1,7 @@ /// describe('Basic API checks', () => { - it('Should return a valid health payload', function () { + it('Should return a valid health payload', () => { cy.task('backendApiGet', { path: '/api/', }).then((data) => { @@ -10,9 +10,9 @@ describe('Basic API checks', () => { }); }); - it('Should return a valid schema payload', function () { + it('Should return a valid schema payload', () => { cy.task('backendApiGet', { - path: '/api/schema?ts=' + Date.now(), + path: `/api/schema?ts=${Date.now()}`, }).then((data) => { expect(data.openapi).to.be.equal('3.1.0'); }); diff --git a/test/cypress/e2e/api/Ldap.cy.js b/test/cypress/e2e/api/Ldap.cy.js index 6b7e5f76..715c793b 100644 --- a/test/cypress/e2e/api/Ldap.cy.js +++ b/test/cypress/e2e/api/Ldap.cy.js @@ -1,12 +1,12 @@ /// describe('LDAP with Authentik', () => { - let token; + let _token; if (Cypress.env('skipStackCheck') === 'true' || Cypress.env('stack') === 'postgres') { before(() => { cy.getToken().then((tok) => { - token = tok; + _token = tok; // cy.task('backendApiPut', { // token: token, @@ -45,7 +45,7 @@ describe('LDAP with Authentik', () => { }); }); - it.skip('Should log in with LDAP', function() { + it.skip('Should log in with LDAP', () => { // cy.task('backendApiPost', { // token: token, // path: '/api/auth', diff --git a/test/cypress/e2e/api/OAuth.cy.js b/test/cypress/e2e/api/OAuth.cy.js index 044bb275..c5c819f9 100644 --- a/test/cypress/e2e/api/OAuth.cy.js +++ b/test/cypress/e2e/api/OAuth.cy.js @@ -1,12 +1,12 @@ /// describe('OAuth with Authentik', () => { - let token; + let _token; if (Cypress.env('skipStackCheck') === 'true' || Cypress.env('stack') === 'postgres') { before(() => { cy.getToken().then((tok) => { - token = tok; + _token = tok; // cy.task('backendApiPut', { // token: token, @@ -47,7 +47,7 @@ describe('OAuth with Authentik', () => { }); }); - it.skip('Should log in with OAuth', function() { + it.skip('Should log in with OAuth', () => { // cy.task('backendApiGet', { // path: '/oauth/login?redirect_base=' + encodeURI(Cypress.config('baseUrl')), // }).then((data) => { diff --git a/test/cypress/e2e/api/ProxyHosts.cy.js b/test/cypress/e2e/api/ProxyHosts.cy.js index 5bc64580..476945e7 100644 --- a/test/cypress/e2e/api/ProxyHosts.cy.js +++ b/test/cypress/e2e/api/ProxyHosts.cy.js @@ -9,7 +9,7 @@ describe('Proxy Hosts endpoints', () => { }); }); - it('Should be able to create a http host', function() { + it('Should be able to create a http host', () => { cy.task('backendApiPost', { token: token, path: '/api/nginx/proxy-hosts', diff --git a/test/cypress/e2e/api/Settings.cy.js b/test/cypress/e2e/api/Settings.cy.js index 6942760c..fcaa0628 100644 --- a/test/cypress/e2e/api/Settings.cy.js +++ b/test/cypress/e2e/api/Settings.cy.js @@ -9,7 +9,7 @@ describe('Settings endpoints', () => { }); }); - it('Get all settings', function() { + it('Get all settings', () => { cy.task('backendApiGet', { token: token, path: '/api/settings', @@ -19,7 +19,7 @@ describe('Settings endpoints', () => { }); }); - it('Get default-site setting', function() { + it('Get default-site setting', () => { cy.task('backendApiGet', { token: token, path: '/api/settings/default-site', @@ -30,7 +30,7 @@ describe('Settings endpoints', () => { }); }); - it('Default Site congratulations', function() { + it('Default Site congratulations', () => { cy.task('backendApiPut', { token: token, path: '/api/settings/default-site', @@ -46,7 +46,7 @@ describe('Settings endpoints', () => { }); }); - it('Default Site 404', function() { + it('Default Site 404', () => { cy.task('backendApiPut', { token: token, path: '/api/settings/default-site', @@ -62,7 +62,7 @@ describe('Settings endpoints', () => { }); }); - it('Default Site 444', function() { + it('Default Site 444', () => { cy.task('backendApiPut', { token: token, path: '/api/settings/default-site', @@ -78,7 +78,7 @@ describe('Settings endpoints', () => { }); }); - it('Default Site redirect', function() { + it('Default Site redirect', () => { cy.task('backendApiPut', { token: token, path: '/api/settings/default-site', @@ -100,7 +100,7 @@ describe('Settings endpoints', () => { }); }); - it('Default Site html', function() { + it('Default Site html', () => { cy.task('backendApiPut', { token: token, path: '/api/settings/default-site', diff --git a/test/cypress/e2e/api/Streams.cy.js b/test/cypress/e2e/api/Streams.cy.js index fce04101..e38f9dba 100644 --- a/test/cypress/e2e/api/Streams.cy.js +++ b/test/cypress/e2e/api/Streams.cy.js @@ -33,7 +33,7 @@ describe('Streams', () => { cy.exec('rm -f /test/results/testssl.json'); }); - it('Should be able to create TCP Stream', function() { + it('Should be able to create TCP Stream', () => { cy.task('backendApiPost', { token: token, path: '/api/nginx/streams', @@ -65,7 +65,7 @@ describe('Streams', () => { }); }); - it('Should be able to create UDP Stream', function() { + it('Should be able to create UDP Stream', () => { cy.task('backendApiPost', { token: token, path: '/api/nginx/streams', @@ -92,7 +92,7 @@ describe('Streams', () => { }); }); - it('Should be able to create TCP/UDP Stream', function() { + it('Should be able to create TCP/UDP Stream', () => { cy.task('backendApiPost', { token: token, path: '/api/nginx/streams', @@ -124,7 +124,7 @@ describe('Streams', () => { }); }); - it('Should be able to create SSL TCP Stream', function() { + it('Should be able to create SSL TCP Stream', () => { let certID = 0; // Create custom cert @@ -184,7 +184,7 @@ describe('Streams', () => { cy.exec('/testssl/testssl.sh --quiet --add-ca="$(/bin/mkcert -CAROOT)/rootCA.pem" --jsonfile=/test/results/testssl.json website1.example.com:1503', { timeout: 120000, // 2 minutes }).then((result) => { - cy.task('log', '[testssl.sh] ' + result.stdout); + cy.task('log', `[testssl.sh] ${result.stdout}`); const allowedSeverities = ["INFO", "OK", "LOW", "MEDIUM"]; const ignoredIDs = [ @@ -210,7 +210,7 @@ describe('Streams', () => { }); }); - it('Should be able to List Streams', function() { + it('Should be able to List Streams', () => { cy.task('backendApiGet', { token: token, path: '/api/nginx/streams?expand=owner,certificate', diff --git a/test/cypress/e2e/api/Users.cy.js b/test/cypress/e2e/api/Users.cy.js index 06b18317..7307f87d 100644 --- a/test/cypress/e2e/api/Users.cy.js +++ b/test/cypress/e2e/api/Users.cy.js @@ -9,7 +9,7 @@ describe('Users endpoints', () => { }); }); - it('Should be able to get yourself', function() { + it('Should be able to get yourself', () => { cy.task('backendApiGet', { token: token, path: '/api/users/me' @@ -20,7 +20,7 @@ describe('Users endpoints', () => { }); }); - it('Should be able to get all users', function() { + it('Should be able to get all users', () => { cy.task('backendApiGet', { token: token, path: '/api/users' @@ -30,7 +30,7 @@ describe('Users endpoints', () => { }); }); - it('Should be able to update yourself', function() { + it('Should be able to update yourself', () => { cy.task('backendApiPut', { token: token, path: '/api/users/me',