Browse Source

Merge pull request #4907 from NginxProxyManager/develop

v2.13.3
jc21 1 month ago
parent
commit
2578105f86

+ 1 - 1
.version

@@ -1 +1 @@
-2.13.2
+2.13.3

+ 1 - 1
README.md

@@ -1,7 +1,7 @@
 <p align="center">
 	<img src="https://nginxproxymanager.com/github.png">
 	<br><br>
-	<img src="https://img.shields.io/badge/version-2.13.2-green.svg?style=for-the-badge">
+	<img src="https://img.shields.io/badge/version-2.13.3-green.svg?style=for-the-badge">
 	<a href="https://hub.docker.com/repository/docker/jc21/nginx-proxy-manager">
 		<img src="https://img.shields.io/docker/stars/jc21/nginx-proxy-manager.svg?style=for-the-badge">
 	</a>

+ 9 - 1
backend/certbot/dns-plugins.json

@@ -370,7 +370,7 @@
 	"leaseweb": {
 		"name": "LeaseWeb",
 		"package_name": "certbot-dns-leaseweb",
-		"version": "~=1.0.1",
+		"version": "~=1.0.3",
 		"dependencies": "",
 		"credentials": "dns_leaseweb_api_token = 01234556789",
 		"full_plugin_name": "dns-leaseweb"
@@ -399,6 +399,14 @@
 		"credentials": "dns_luadns_email = [email protected]\ndns_luadns_token = 0123456789abcdef0123456789abcdef",
 		"full_plugin_name": "dns-luadns"
 	},
+	"mchost24": {
+		"name": "MC-HOST24",
+		"package_name": "certbot-dns-mchost24",
+		"version": "",
+		"dependencies": "",
+		"credentials": "# Obtain API token using https://github.com/JoeJoeTV/mchost24-api-python\ndns_mchost24_api_token=<insert obtained API token here>",
+		"full_plugin_name": "dns-mchost24"
+	},
 	"mijnhost": {
 		"name": "mijn.host",
 		"package_name": "certbot-dns-mijn-host",

+ 5 - 0
backend/internal/nginx.js

@@ -216,6 +216,11 @@ const internalNginx = {
 				}
 			}
 
+			// For redirection hosts, if the scheme is not http or https, set it to $scheme
+			if (nice_host_type === "redirection_host" && ['http', 'https'].indexOf(host.forward_scheme.toLowerCase()) === -1) {
+				host.forward_scheme = "$scheme";
+			}
+
 			if (host.locations) {
 				//logger.info ('host.locations = ' + JSON.stringify(host.locations, null, 2));
 				origLocations = [].concat(host.locations);

+ 50 - 0
backend/migrations/20251111090000_redirect_auto_scheme.js

@@ -0,0 +1,50 @@
+import { migrate as logger } from "../logger.js";
+
+const migrateName = "redirect_auto_scheme";
+
+/**
+ * Migrate
+ *
+ * @see http://knexjs.org/#Schema
+ *
+ * @param   {Object} knex
+ * @returns {Promise}
+ */
+const up = (knex) => {
+	logger.info(`[${migrateName}] Migrating Up...`);
+
+	return knex.schema
+		.table("redirection_host", async (table) => {
+			// change the column default from $scheme to auto
+			await table.string("forward_scheme").notNull().defaultTo("auto").alter();
+			await knex('redirection_host')
+				.where('forward_scheme', '$scheme')
+				.update({ forward_scheme: 'auto' });
+		})
+		.then(() => {
+			logger.info(`[${migrateName}] redirection_host Table altered`);
+		});
+};
+
+/**
+ * Undo Migrate
+ *
+ * @param   {Object} knex
+ * @returns {Promise}
+ */
+const down = (knex) => {
+	logger.info(`[${migrateName}] Migrating Down...`);
+
+	return knex.schema
+		.table("redirection_host", async (table) => {
+			await table.string("forward_scheme").notNull().defaultTo("$scheme").alter();
+			await knex('redirection_host')
+				.where('forward_scheme', 'auto')
+				.update({ forward_scheme: '$scheme' });
+		})
+		.then(() => {
+			logger.info(`[${migrateName}] redirection_host Table altered`);
+		});
+};
+
+export { up, down };

+ 2 - 2
backend/setup.js

@@ -37,7 +37,7 @@ const setupDefaultUser = async () => {
 
 		const data = {
 			is_deleted: 0,
-			email: email,
+			email: initialAdminEmail,
 			name: "Administrator",
 			nickname: "Admin",
 			avatar: "",
@@ -53,7 +53,7 @@ const setupDefaultUser = async () => {
 			.insert({
 				user_id: user.id,
 				type: "password",
-				secret: password,
+				secret: initialAdminPassword,
 				meta: {},
 			});
 

+ 1 - 1
backend/templates/_access.conf

@@ -4,7 +4,7 @@
     auth_basic            "Authorization required";
     auth_basic_user_file  /data/access/{{ access_list_id }};
 
-    {% if access_list.pass_auth == 0 or access_list.pass_auth == true %}
+    {% if access_list.pass_auth == 0 or access_list.pass_auth == false %}
     proxy_set_header Authorization "";
     {% endif %}
 

+ 1 - 1
docker/ci.env

@@ -1,6 +1,6 @@
 AUTHENTIK_SECRET_KEY=gl8woZe8L6IIX8SC0c5Ocsj0xPkX5uJo5DVZCFl+L/QGbzuplfutYuua2ODNLEiDD3aFd9H2ylJmrke0
 AUTHENTIK_REDIS__HOST=authentik-redis
-AUTHENTIK_POSTGRESQL__HOST=db-postgres
+AUTHENTIK_POSTGRESQL__HOST=pgdb.internal
 AUTHENTIK_POSTGRESQL__USER=authentik
 AUTHENTIK_POSTGRESQL__NAME=authentik
 AUTHENTIK_POSTGRESQL__PASSWORD=07EKS5NLI6Tpv68tbdvrxfvj

+ 12 - 2
docker/docker-compose.ci.postgres.yml

@@ -6,7 +6,7 @@ services:
 
   fullstack:
     environment:
-      DB_POSTGRES_HOST: "db-postgres"
+      DB_POSTGRES_HOST: "pgdb.internal"
       DB_POSTGRES_PORT: "5432"
       DB_POSTGRES_USER: "npm"
       DB_POSTGRES_PASSWORD: "npmpass"
@@ -27,7 +27,9 @@ services:
       - psql_vol:/var/lib/postgresql/data
       - ./ci/postgres:/docker-entrypoint-initdb.d
     networks:
-      - fulltest
+      fulltest:
+        aliases:
+          - pgdb.internal
 
   authentik-redis:
     image: "redis:alpine"
@@ -41,6 +43,8 @@ services:
       timeout: 3s
     volumes:
       - redis_vol:/data
+    networks:
+      - fulltest
 
   authentik:
     image: ghcr.io/goauthentik/server:2024.10.1
@@ -51,6 +55,8 @@ services:
     depends_on:
       - authentik-redis
       - db-postgres
+    networks:
+      - fulltest
 
   authentik-worker:
     image: ghcr.io/goauthentik/server:2024.10.1
@@ -61,6 +67,8 @@ services:
     depends_on:
       - authentik-redis
       - db-postgres
+    networks:
+      - fulltest
 
   authentik-ldap:
     image: ghcr.io/goauthentik/ldap:2024.10.1
@@ -71,6 +79,8 @@ services:
     restart: unless-stopped
     depends_on:
       - authentik
+    networks:
+      - fulltest
 
 volumes:
   psql_vol:

+ 39 - 40
docker/docker-compose.ci.yml

@@ -3,31 +3,30 @@
 # This is a base compose file, it should be extended with a
 # docker-compose.ci.*.yml file
 services:
-
   fullstack:
     image: "${IMAGE}:${BRANCH_LOWER}-ci-${BUILD_NUMBER}"
     environment:
       TZ: "${TZ:-Australia/Brisbane}"
-      DEBUG: 'true'
-      CI: 'true'
+      DEBUG: "true"
+      CI: "true"
       FORCE_COLOR: 1
       # Required for DNS Certificate provisioning in CI
-      LE_SERVER: 'https://ca.internal/acme/acme/directory'
-      REQUESTS_CA_BUNDLE: '/etc/ssl/certs/NginxProxyManager.crt'
+      LE_SERVER: "https://ca.internal/acme/acme/directory"
+      REQUESTS_CA_BUNDLE: "/etc/ssl/certs/NginxProxyManager.crt"
     volumes:
-      - 'npm_data_ci:/data'
-      - 'npm_le_ci:/etc/letsencrypt'
-      - './dev/letsencrypt.ini:/etc/letsencrypt.ini:ro'
-      - './dev/resolv.conf:/etc/resolv.conf:ro'
-      - '/etc/localtime:/etc/localtime:ro'
+      - "npm_data_ci:/data"
+      - "npm_le_ci:/etc/letsencrypt"
+      - "./dev/letsencrypt.ini:/etc/letsencrypt.ini:ro"
+      - "./dev/resolv.conf:/etc/resolv.conf:ro"
+      - "/etc/localtime:/etc/localtime:ro"
     healthcheck:
       test: ["CMD", "/usr/bin/check-health"]
       interval: 10s
       timeout: 3s
     expose:
-      - '80-81/tcp'
-      - '443/tcp'
-      - '1500-1503/tcp'
+      - "80-81/tcp"
+      - "443/tcp"
+      - "1500-1503/tcp"
     networks:
       fulltest:
         aliases:
@@ -38,8 +37,8 @@ services:
   stepca:
     image: jc21/testca
     volumes:
-      - './dev/resolv.conf:/etc/resolv.conf:ro'
-      - '/etc/localtime:/etc/localtime:ro'
+      - "./dev/resolv.conf:/etc/resolv.conf:ro"
+      - "/etc/localtime:/etc/localtime:ro"
     networks:
       fulltest:
         aliases:
@@ -48,18 +47,18 @@ services:
   pdns:
     image: pschiffe/pdns-mysql:4.8
     volumes:
-      - '/etc/localtime:/etc/localtime:ro'
+      - "/etc/localtime:/etc/localtime:ro"
     environment:
-      PDNS_master: 'yes'
-      PDNS_api: 'yes'
-      PDNS_api_key: 'npm'
-      PDNS_webserver: 'yes'
-      PDNS_webserver_address: '0.0.0.0'
-      PDNS_webserver_password: 'npm'
-      PDNS_webserver-allow-from: '127.0.0.0/8,192.0.0.0/8,10.0.0.0/8,172.0.0.0/8'
-      PDNS_version_string: 'anonymous'
+      PDNS_master: "yes"
+      PDNS_api: "yes"
+      PDNS_api_key: "npm"
+      PDNS_webserver: "yes"
+      PDNS_webserver_address: "0.0.0.0"
+      PDNS_webserver_password: "npm"
+      PDNS_webserver-allow-from: "127.0.0.0/8,192.0.0.0/8,10.0.0.0/8,172.0.0.0/8"
+      PDNS_version_string: "anonymous"
       PDNS_default_ttl: 1500
-      PDNS_allow_axfr_ips: '127.0.0.0/8,192.0.0.0/8,10.0.0.0/8,172.0.0.0/8'
+      PDNS_allow_axfr_ips: "127.0.0.0/8,192.0.0.0/8,10.0.0.0/8,172.0.0.0/8"
       PDNS_gmysql_host: pdns-db
       PDNS_gmysql_port: 3306
       PDNS_gmysql_user: pdns
@@ -76,14 +75,14 @@ services:
   pdns-db:
     image: mariadb
     environment:
-      MYSQL_ROOT_PASSWORD: 'pdns'
-      MYSQL_DATABASE: 'pdns'
-      MYSQL_USER: 'pdns'
-      MYSQL_PASSWORD: 'pdns'
+      MYSQL_ROOT_PASSWORD: "pdns"
+      MYSQL_DATABASE: "pdns"
+      MYSQL_USER: "pdns"
+      MYSQL_PASSWORD: "pdns"
     volumes:
-      - 'pdns_mysql_vol:/var/lib/mysql'
-      - '/etc/localtime:/etc/localtime:ro'
-      - './dev/pdns-db.sql:/docker-entrypoint-initdb.d/01_init.sql:ro'
+      - "pdns_mysql_vol:/var/lib/mysql"
+      - "/etc/localtime:/etc/localtime:ro"
+      - "./dev/pdns-db.sql:/docker-entrypoint-initdb.d/01_init.sql:ro"
     networks:
       - fulltest
 
@@ -100,12 +99,12 @@ services:
       context: ../
       dockerfile: test/cypress/Dockerfile
     environment:
-      HTTP_PROXY: 'squid:3128'
-      HTTPS_PROXY: 'squid:3128'
+      HTTP_PROXY: "squid:3128"
+      HTTPS_PROXY: "squid:3128"
     volumes:
-      - 'cypress_logs:/test/results'
-      - './dev/resolv.conf:/etc/resolv.conf:ro'
-      - '/etc/localtime:/etc/localtime:ro'
+      - "cypress_logs:/test/results"
+      - "./dev/resolv.conf:/etc/resolv.conf:ro"
+      - "/etc/localtime:/etc/localtime:ro"
     command: cypress run --browser chrome --config-file=cypress/config/ci.js
     networks:
       - fulltest
@@ -113,9 +112,9 @@ services:
   squid:
     image: ubuntu/squid
     volumes:
-      - './dev/squid.conf:/etc/squid/squid.conf:ro'
-      - './dev/resolv.conf:/etc/resolv.conf:ro'
-      - '/etc/localtime:/etc/localtime:ro'
+      - "./dev/squid.conf:/etc/squid/squid.conf:ro"
+      - "./dev/resolv.conf:/etc/resolv.conf:ro"
+      - "/etc/localtime:/etc/localtime:ro"
     networks:
       - fulltest
 

+ 5 - 3
docker/docker-compose.dev.yml

@@ -32,7 +32,7 @@ services:
       # DB_MYSQL_PASSWORD: 'npm'
       # DB_MYSQL_NAME: 'npm'
       # db-postgres:
-      DB_POSTGRES_HOST: "db-postgres"
+      DB_POSTGRES_HOST: "pgdb.internal"
       DB_POSTGRES_PORT: "5432"
       DB_POSTGRES_USER: "npm"
       DB_POSTGRES_PASSWORD: "npmpass"
@@ -81,8 +81,6 @@ services:
   db-postgres:
     image: postgres:17
     container_name: npm2dev.db-postgres
-    networks:
-      - nginx_proxy_manager
     environment:
       POSTGRES_USER: "npm"
       POSTGRES_PASSWORD: "npmpass"
@@ -90,6 +88,10 @@ services:
     volumes:
       - psql_data:/var/lib/postgresql/data
       - ./ci/postgres:/docker-entrypoint-initdb.d
+    networks:
+      nginx_proxy_manager:
+        aliases:
+          - pgdb.internal
 
   stepca:
     image: jc21/testca

+ 1 - 1
frontend/src/components/SiteMenu.tsx

@@ -190,7 +190,7 @@ export function SiteMenu() {
 
 	return (
 		<header className="navbar-expand-md">
-			<div className="collapse navbar-collapse">
+			<div className="collapse navbar-collapse"  id="navbar-menu">
 				<div className="navbar">
 					<div className="container-xl">
 						<div className="row flex-column flex-md-row flex-fill align-items-center">

+ 1 - 0
frontend/src/locale/lang/en.json

@@ -169,6 +169,7 @@
   "public": "Public",
   "redirection-host": "Redirection Host",
   "redirection-host.forward-domain": "Forward Domain",
+  "redirection-host.forward-http-code": "HTTP Code",
   "redirection-hosts": "Redirection Hosts",
   "redirection-hosts.count": "{count} {count, plural, one {Redirection Host} other {Redirection Hosts}}",
   "role.admin": "Administrator",

+ 3 - 0
frontend/src/locale/src/en.json

@@ -509,6 +509,9 @@
 	"redirection-host.forward-domain": {
 		"defaultMessage": "Forward Domain"
 	},
+	"redirection-host.forward-http-code": {
+		"defaultMessage": "HTTP Code"
+	},
 	"redirection-hosts": {
 		"defaultMessage": "Redirection Hosts"
 	},

+ 31 - 1
frontend/src/modals/RedirectionHostModal.tsx

@@ -162,7 +162,7 @@ const RedirectionHostModal = EasyModal.create(({ id, visible, remove }: Props) =
 																		required
 																		{...field}
 																	>
-																		<option value="$scheme">Auto</option>
+																		<option value="auto">Auto</option>
 																		<option value="http">http</option>
 																		<option value="https">https</option>
 																	</select>
@@ -212,6 +212,36 @@ const RedirectionHostModal = EasyModal.create(({ id, visible, remove }: Props) =
 														</Field>
 													</div>
 												</div>
+												<Field name="forwardHttpCode">
+													{({ field, form }: any) => (
+														<div className="mb-3">
+															<label className="form-label" htmlFor="forwardHttpCode">
+																<T id="redirection-host.forward-http-code" />
+															</label>
+															<select
+																id="forwardHttpCode"
+																className={`form-control ${form.errors.forwardHttpCode && form.touched.forwardHttpCode ? "is-invalid" : ""}`}
+																required
+																{...field}
+															>
+																<option value="300">300 Multiple choices</option>
+																<option value="301">301 Moved permanently</option>
+																<option value="302">302 Moved temporarily</option>
+																<option value="303">303 See other</option>
+																<option value="307">307 Temporary redirect</option>
+																<option value="308">308 Permanent redirect</option>
+															</select>
+															{form.errors.forwardHttpCode ? (
+																<div className="invalid-feedback">
+																	{form.errors.forwardHttpCode &&
+																	form.touched.forwardHttpCode
+																		? form.errors.forwardHttpCode
+																		: null}
+																</div>
+															) : null}
+														</div>
+													)}
+												</Field>
 												<div className="my-3">
 													<h4 className="py-2">
 														<T id="options" />

+ 1 - 1
frontend/src/modules/Validations.tsx

@@ -44,7 +44,7 @@ const validateEmail = () => {
 		if (!value.length) {
 			return intl.formatMessage({ id: "error.required" });
 		}
-		if (!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(value)) {
+		if (!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+$/i.test(value)) {
 			return intl.formatMessage({ id: "error.invalid-email" });
 		}
 	};