浏览代码

Merge pull request #1716 from jc21/develop

v2.9.14
jc21 3 年之前
父节点
当前提交
081380c8d5

+ 1 - 1
.version

@@ -1 +1 @@
-2.9.13
+2.9.14

+ 1 - 0
Jenkinsfile

@@ -62,6 +62,7 @@ pipeline {
 		stage('Backend') {
 			steps {
 				echo 'Checking Syntax ...'
+				sh 'docker pull node:latest'
 				// See: https://github.com/yarnpkg/yarn/issues/3254
 				sh '''docker run --rm \\
 					-v "$(pwd)/backend:/app" \\

+ 27 - 7
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.9.13-green.svg?style=for-the-badge">
+	<img src="https://img.shields.io/badge/version-2.9.14-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>
@@ -110,9 +110,9 @@ Special thanks to the following contributors:
 <table>
 	<tr>
 		<td align="center">
-			<a href="https://github.com/Subv">
-				<img src="https://avatars1.githubusercontent.com/u/357072?s=460&u=d8adcdc91d749ae53e177973ed9b6bb6c4c894a3&v=4" width="80" alt=""/>
-				<br /><sub><b>Sebastian Valle</b></sub>
+			<a href="https://github.com/chaptergy">
+				<img src="https://avatars2.githubusercontent.com/u/26956711?s=460&u=7d9adebabb6b4e7af7cb05d98d751087a372304b&v=4" width="80" alt=""/>
+				<br /><sub><b>chaptergy</b></sub>
 			</a>
 		</td>
 		<td align="center">
@@ -242,9 +242,9 @@ Special thanks to the following contributors:
 	</tr>
 	<tr>
 		<td align="center">
-			<a href="https://github.com/chaptergy">
-				<img src="https://avatars2.githubusercontent.com/u/26956711?s=460&u=7d9adebabb6b4e7af7cb05d98d751087a372304b&v=4" width="80" alt=""/>
-				<br /><sub><b>chaptergy</b></sub>
+			<a href="https://github.com/Subv">
+				<img src="https://avatars1.githubusercontent.com/u/357072?s=460&u=d8adcdc91d749ae53e177973ed9b6bb6c4c894a3&v=4" width="80" alt=""/>
+				<br /><sub><b>Sebastian Valle</b></sub>
 			</a>
 		</td>
 		<td align="center">
@@ -491,6 +491,26 @@ Special thanks to the following contributors:
 				<br /><sub><b>bergi9</b></sub>
 			</a>
 		</td>
+		<td align="center">
+			<a href="https://github.com/luoweihua7">
+				<img src="https://avatars.githubusercontent.com/u/3157520?v=4" width="80" alt=""/>
+				<br /><sub><b>luoweihua7</b></sub>
+			</a>
+		</td>
+		<td align="center">
+			<a href="https://github.com/TobiasKneidl">
+				<img src="https://avatars.githubusercontent.com/u/26301707?v=4" width="80" alt=""/>
+				<br /><sub><b>Tobias Kneidl</b></sub>
+			</a>
+		</td>
+	</tr>
+	<tr>
+		<td align="center">
+			<a href="https://github.com/piuswalter">
+				<img src="https://avatars.githubusercontent.com/u/64539242?v=4" width="80" alt=""/>
+				<br /><sub><b>Pius Walter</b></sub>
+			</a>
+		</td>
 	</tr>
 </table>
 <!-- markdownlint-enable -->

+ 5 - 2
backend/internal/certificate.js

@@ -171,6 +171,7 @@ const internalCertificate = {
 								// 3. Generate the LE config
 								return internalNginx.generateLetsEncryptRequestConfig(certificate)
 									.then(internalNginx.reload)
+									.then(async() => await new Promise((r) => setTimeout(r, 5000)))
 									.then(() => {
 										// 4. Request cert
 										return internalCertificate.requestLetsEncryptSsl(certificate);
@@ -870,8 +871,10 @@ const internalCertificate = {
 		logger.info(`Requesting Let'sEncrypt certificates via ${dns_plugin.display_name} for Cert #${certificate.id}: ${certificate.domain_names.join(', ')}`);
 
 		const credentialsLocation = '/etc/letsencrypt/credentials/credentials-' + certificate.id;
-		const credentialsCmd      = 'mkdir -p /etc/letsencrypt/credentials 2> /dev/null; echo \'' + certificate.meta.dns_provider_credentials.replace('\'', '\\\'') + '\' > \'' + credentialsLocation + '\' && chmod 600 \'' + credentialsLocation + '\'';
-		const prepareCmd          = 'pip install ' + dns_plugin.package_name + (dns_plugin.version_requirement || '') + ' ' + dns_plugin.dependencies;
+		// Escape single quotes and backslashes
+		const escapedCredentials = certificate.meta.dns_provider_credentials.replaceAll('\'', '\\\'').replaceAll('\\', '\\\\');
+		const credentialsCmd     = 'mkdir -p /etc/letsencrypt/credentials 2> /dev/null; echo \'' + escapedCredentials + '\' > \'' + credentialsLocation + '\' && chmod 600 \'' + credentialsLocation + '\'';
+		const prepareCmd         = 'pip install ' + dns_plugin.package_name + (dns_plugin.version_requirement || '') + ' ' + dns_plugin.dependencies;
 
 		// Whether the plugin has a --<name>-credentials argument
 		const hasConfigArg = certificate.meta.dns_provider !== 'route53';

+ 5 - 2
backend/internal/ip_ranges.js

@@ -9,6 +9,9 @@ const CLOUDFRONT_URL   = 'https://ip-ranges.amazonaws.com/ip-ranges.json';
 const CLOUDFARE_V4_URL = 'https://www.cloudflare.com/ips-v4';
 const CLOUDFARE_V6_URL = 'https://www.cloudflare.com/ips-v6';
 
+const regIpV4 = /^(\d+\.?){4}\/\d+/;
+const regIpV6 = /^(([\da-fA-F]+)?:)+\/\d+/;
+
 const internalIpRanges = {
 
 	interval_timeout:    1000 * 60 * 60 * 6, // 6 hours
@@ -74,14 +77,14 @@ const internalIpRanges = {
 					return internalIpRanges.fetchUrl(CLOUDFARE_V4_URL);
 				})
 				.then((cloudfare_data) => {
-					let items = cloudfare_data.split('\n');
+					let items = cloudfare_data.split('\n').filter((line) => regIpV4.test(line));
 					ip_ranges = [... ip_ranges, ... items];
 				})
 				.then(() => {
 					return internalIpRanges.fetchUrl(CLOUDFARE_V6_URL);
 				})
 				.then((cloudfare_data) => {
-					let items = cloudfare_data.split('\n');
+					let items = cloudfare_data.split('\n').filter((line) => regIpV6.test(line));
 					ip_ranges = [... ip_ranges, ... items];
 				})
 				.then(() => {

+ 3 - 1
backend/setup.js

@@ -181,7 +181,9 @@ const setupCertbotPlugins = () => {
 
 						// Make sure credentials file exists
 						const credentials_loc = '/etc/letsencrypt/credentials/credentials-' + certificate.id; 
-						const credentials_cmd = '[ -f \'' + credentials_loc + '\' ] || { mkdir -p /etc/letsencrypt/credentials 2> /dev/null; echo \'' + certificate.meta.dns_provider_credentials.replace('\'', '\\\'') + '\' > \'' + credentials_loc + '\' && chmod 600 \'' + credentials_loc + '\'; }';
+						// Escape single quotes and backslashes
+						const escapedCredentials = certificate.meta.dns_provider_credentials.replaceAll('\'', '\\\'').replaceAll('\\', '\\\\');
+						const credentials_cmd    = '[ -f \'' + credentials_loc + '\' ] || { mkdir -p /etc/letsencrypt/credentials 2> /dev/null; echo \'' + escapedCredentials + '\' > \'' + credentials_loc + '\' && chmod 600 \'' + credentials_loc + '\'; }';
 						promises.push(utils.exec(credentials_cmd));
 					}
 				});

+ 2 - 2
backend/templates/default.conf

@@ -7,9 +7,9 @@
 server {
   listen 80 default;
 {% if ipv6 -%}
-  listen [::]:80;
+  listen [::]:80 default;
 {% else -%}
-  #listen [::]:80;
+  #listen [::]:80 default;
 {% endif %}
   server_name default-host.localhost;
   access_log /data/logs/default-host_access.log combined;

+ 1 - 1
docker/rootfs/etc/nginx/conf.d/default.conf

@@ -30,7 +30,7 @@ server {
 	set $port "443";
 
 	server_name localhost;
-	access_log /data/logs/fallback-access.log standard;
+	access_log /data/logs/fallback_access.log standard;
 	error_log /dev/null crit;
 	ssl_certificate /data/nginx/dummycert.pem;
 	ssl_certificate_key /data/nginx/dummykey.pem;

+ 2 - 0
docker/rootfs/etc/nginx/conf.d/include/proxy.conf

@@ -2,6 +2,8 @@ add_header       X-Served-By $host;
 proxy_set_header Host $host;
 proxy_set_header X-Forwarded-Scheme $scheme;
 proxy_set_header X-Forwarded-Proto  $scheme;
+proxy_set_header X-Forwarded-Host   $host;
+proxy_set_header X-Forwarded-Port   $port;
 proxy_set_header X-Forwarded-For    $remote_addr;
 proxy_set_header X-Real-IP          $remote_addr;
 proxy_pass       $forward_scheme://$server:$port$request_uri;

+ 1 - 1
docker/rootfs/etc/services.d/nginx/run

@@ -24,7 +24,7 @@ chown root /tmp/nginx
 
 # Dynamically generate resolvers file, if resolver is IPv6, enclose in `[]`
 # thanks @tfmm
-echo resolver "$(awk 'BEGIN{ORS=" "} $1=="nameserver" {print ($2 ~ ":")? "["$2"]": $2}' /etc/resolv.conf);" > /etc/nginx/conf.d/include/resolvers.conf
+echo resolver "$(awk 'BEGIN{ORS=" "} $1=="nameserver" { sub(/%.*$/,"",$2); print ($2 ~ ":")? "["$2"]": $2}' /etc/resolv.conf);" > /etc/nginx/conf.d/include/resolvers.conf
 
 # Generate dummy self-signed certificate.
 if [ ! -f /data/nginx/dummycert.pem ] || [ ! -f /data/nginx/dummykey.pem ]

+ 3 - 0
docs/faq/README.md

@@ -21,3 +21,6 @@ Your best bet is to ask the [Reddit community for support](https://www.reddit.co
 
 Gitter is best left for anyone contributing to the project to ask for help about internals, code reviews etc.
 
+## When adding username and password access control to a proxy host, I can no longer login into the app.
+
+Having an Access Control List (ACL) with username and password requires the browser to always send this username and password in the `Authorization` header on each request. If your proxied app also requires authentication (like Nginx Proxy Manager itself), most likely the app will also use the `Authorization` header to transmit this information, as this is the standardized header meant for this kind of information. However having multiples of the same headers is not allowed in the [internet standard](https://www.rfc-editor.org/rfc/rfc7230#section-3.2.2) and almost all apps do not support multiple values in the `Authorization` header. Hence one of the two logins will be broken. This can only be fixed by either removing one of the logins or by changing the app to use other non-standard headers for authorization.

+ 5 - 3
frontend/js/app/nginx/certificates/form.js

@@ -278,9 +278,11 @@ module.exports = Mn.View.extend({
         this.ui.credentials_file_content.hide(); 
         this.ui.loader_content.hide();
         this.ui.le_error_info.hide();
-        const domainNames = this.ui.domain_names[0].value.split(',');
-        if (!domainNames || domainNames.length === 0 || (domainNames.length === 1 && domainNames[0] === "")) {
-            this.ui.test_domains_button.prop('disabled', true);
+        if (this.ui.domain_names[0]) {
+            const domainNames = this.ui.domain_names[0].value.split(',');
+            if (!domainNames || domainNames.length === 0 || (domainNames.length === 1 && domainNames[0] === "")) {
+                this.ui.test_domains_button.prop('disabled', true);
+            }
         }
     },
 

+ 75 - 65
global/certbot-dns-plugins.js

@@ -67,11 +67,11 @@ dns_azure_zone2 = example.org:/subscriptions/99800903-fb14-4992-9aff-12eaf274462
 	},
 	//####################################################//
 	cloudflare: {
-		display_name: 'Cloudflare',
-		package_name: 'certbot-dns-cloudflare',
-		// version_requirement: '', // Official plugin, no version requirement
-		dependencies: 'cloudflare',
-		credentials:  `# Cloudflare API token
+		display_name:        'Cloudflare',
+		package_name:        'certbot-dns-cloudflare',
+		version_requirement: '==$(certbot --version | grep -Eo \'[0-9](\\.[0-9]+)+\')', // official plugin, use certbot version
+		dependencies:        'cloudflare',
+		credentials:         `# Cloudflare API token
 dns_cloudflare_api_token = 0123456789abcdef0123456789abcdef01234567`,
 		full_plugin_name: 'dns-cloudflare',
 	},
@@ -93,11 +93,11 @@ dns_cloudflare_api_token = 0123456789abcdef0123456789abcdef01234567`,
 	},
 	//####################################################//
 	cloudxns: {
-		display_name: 'CloudXNS',
-		package_name: 'certbot-dns-cloudxns',
-		// version_requirement: '', // Official plugin, no version requirement
-		dependencies: '',
-		credentials:  `dns_cloudxns_api_key = 1234567890abcdef1234567890abcdef
+		display_name:        'CloudXNS',
+		package_name:        'certbot-dns-cloudxns',
+		version_requirement: '==$(certbot --version | grep -Eo \'[0-9](\\.[0-9]+)+\')', // official plugin, use certbot version
+		dependencies:        '',
+		credentials:         `dns_cloudxns_api_key = 1234567890abcdef1234567890abcdef
 dns_cloudxns_secret_key = 1122334455667788`,
 		full_plugin_name: 'dns-cloudxns',
 	},
@@ -143,12 +143,12 @@ dns_desec_endpoint = https://desec.io/api/v1/`,
 	},
 	//####################################################//
 	digitalocean: {
-		display_name:     'DigitalOcean',
-		package_name:     'certbot-dns-digitalocean',
-		// version_requirement: '', // Official plugin, no version requirement
-		dependencies:     '',
-		credentials:      'dns_digitalocean_token = 0000111122223333444455556666777788889999aaaabbbbccccddddeeeeffff',
-		full_plugin_name: 'dns-digitalocean',
+		display_name:        'DigitalOcean',
+		package_name:        'certbot-dns-digitalocean',
+		version_requirement: '==$(certbot --version | grep -Eo \'[0-9](\\.[0-9]+)+\')', // official plugin, use certbot version
+		dependencies:        '',
+		credentials:         'dns_digitalocean_token = 0000111122223333444455556666777788889999aaaabbbbccccddddeeeeffff',
+		full_plugin_name:    'dns-digitalocean',
 	},
 	//####################################################//
 	directadmin: {
@@ -163,20 +163,20 @@ directadmin_password = aSuperStrongPassword`,
 	},
 	//####################################################//
 	dnsimple: {
-		display_name:     'DNSimple',
-		package_name:     'certbot-dns-dnsimple',
-		// version_requirement: '', // Official plugin, no version requirement
-		dependencies:     '',
-		credentials:      'dns_dnsimple_token = MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw',
-		full_plugin_name: 'dns-dnsimple',
+		display_name:        'DNSimple',
+		package_name:        'certbot-dns-dnsimple',
+		version_requirement: '==$(certbot --version | grep -Eo \'[0-9](\\.[0-9]+)+\')', // official plugin, use certbot version
+		dependencies:        '',
+		credentials:         'dns_dnsimple_token = MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw',
+		full_plugin_name:    'dns-dnsimple',
 	},
 	//####################################################//
 	dnsmadeeasy: {
-		display_name: 'DNS Made Easy',
-		package_name: 'certbot-dns-dnsmadeeasy',
-		// version_requirement: '', // Official plugin, no version requirement
-		dependencies: '',
-		credentials:  `dns_dnsmadeeasy_api_key = 1c1a3c91-4770-4ce7-96f4-54c0eb0e457a
+		display_name:        'DNS Made Easy',
+		package_name:        'certbot-dns-dnsmadeeasy',
+		version_requirement: '==$(certbot --version | grep -Eo \'[0-9](\\.[0-9]+)+\')', // official plugin, use certbot version
+		dependencies:        '',
+		credentials:         `dns_dnsmadeeasy_api_key = 1c1a3c91-4770-4ce7-96f4-54c0eb0e457a
 dns_dnsmadeeasy_secret_key = c9b5625f-9834-4ff8-baba-4ed5f32cae55`,
 		full_plugin_name: 'dns-dnsmadeeasy',
 	},
@@ -186,8 +186,8 @@ dns_dnsmadeeasy_secret_key = c9b5625f-9834-4ff8-baba-4ed5f32cae55`,
 		package_name:        'certbot-dns-dnspod',
 		version_requirement: '~=0.1.0',
 		dependencies:        '',
-		credentials:         `dns_dnspod_email = "DNSPOD-API-REQUIRES-A-VALID-EMAIL"
-dns_dnspod_api_token = "DNSPOD-API-TOKEN"`,
+		credentials:         `dns_dnspod_email = "[email protected]"
+dns_dnspod_api_token = "id,key"`,
 		full_plugin_name: 'dns-dnspod',
 	},
 	//####################################################//
@@ -235,11 +235,11 @@ dns_godaddy_key = abcdef0123456789abcdef01234567abcdef0123`,
 	},
 	//####################################################//
 	google: {
-		display_name: 'Google',
-		package_name: 'certbot-dns-google',
-		// version_requirement: '', // Official plugin, no version requirement
-		dependencies: '',
-		credentials:  `{
+		display_name:        'Google',
+		package_name:        'certbot-dns-google',
+		version_requirement: '==$(certbot --version | grep -Eo \'[0-9](\\.[0-9]+)+\')', // official plugin, use certbot version
+		dependencies:        '',
+		credentials:         `{
 "type": "service_account",
 ...
 }`,
@@ -319,11 +319,11 @@ dns_joker_domain = <Dynamic DNS Domain>`,
 	},
 	//####################################################//
 	linode: {
-		display_name: 'Linode',
-		package_name: 'certbot-dns-linode',
-		// version_requirement: '', // Official plugin, no version requirement
-		dependencies: '',
-		credentials:  `dns_linode_key = 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ64
+		display_name:        'Linode',
+		package_name:        'certbot-dns-linode',
+		version_requirement: '==$(certbot --version | grep -Eo \'[0-9](\\.[0-9]+)+\')', // official plugin, use certbot version
+		dependencies:        '',
+		credentials:         `dns_linode_key = 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ64
 dns_linode_version = [<blank>|3|4]`,
 		full_plugin_name: 'dns-linode',
 	},
@@ -339,11 +339,11 @@ dns_loopia_password = abcdef0123456789abcdef01234567abcdef0123`,
 	},
 	//####################################################//
 	luadns: {
-		display_name: 'LuaDNS',
-		package_name: 'certbot-dns-luadns',
-		// version_requirement: '', // Official plugin, no version requirement
-		dependencies: '',
-		credentials:  `dns_luadns_email = [email protected]
+		display_name:        'LuaDNS',
+		package_name:        'certbot-dns-luadns',
+		version_requirement: '==$(certbot --version | grep -Eo \'[0-9](\\.[0-9]+)+\')', // official plugin, use certbot version
+		dependencies:        '',
+		credentials:         `dns_luadns_email = [email protected]
 dns_luadns_token = 0123456789abcdef0123456789abcdef`,
 		full_plugin_name: 'dns-luadns',
 	},
@@ -369,12 +369,12 @@ dns_netcup_api_password = abcdef0123456789abcdef01234567abcdef0123`,
 	},
 	//####################################################//
 	nsone: {
-		display_name:     'NS1',
-		package_name:     'certbot-dns-nsone',
-		// version_requirement: '', // Official plugin, no version requirement
-		dependencies:     '',
-		credentials:      'dns_nsone_api_key = MDAwMDAwMDAwMDAwMDAw',
-		full_plugin_name: 'dns-nsone',
+		display_name:        'NS1',
+		package_name:        'certbot-dns-nsone',
+		version_requirement: '==$(certbot --version | grep -Eo \'[0-9](\\.[0-9]+)+\')', // official plugin, use certbot version
+		dependencies:        '',
+		credentials:         'dns_nsone_api_key = MDAwMDAwMDAwMDAwMDAw',
+		full_plugin_name:    'dns-nsone',
 	},
 	//####################################################//
 	oci: {
@@ -392,11 +392,11 @@ key_file = ~/.oci/oci_api_key.pem`,
 	},
 	//####################################################//
 	ovh: {
-		display_name: 'OVH',
-		package_name: 'certbot-dns-ovh',
-		// version_requirement: '', // Official plugin, no version requirement
-		dependencies: '',
-		credentials:  `dns_ovh_endpoint = ovh-eu
+		display_name:        'OVH',
+		package_name:        'certbot-dns-ovh',
+		version_requirement: '==$(certbot --version | grep -Eo \'[0-9](\\.[0-9]+)+\')', // official plugin, use certbot version
+		dependencies:        '',
+		credentials:         `dns_ovh_endpoint = ovh-eu
 dns_ovh_application_key = MDAwMDAwMDAwMDAw
 dns_ovh_application_secret = MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw
 dns_ovh_consumer_key = MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw`,
@@ -434,11 +434,11 @@ certbot_regru:dns_password=password`,
 	},
 	//####################################################//
 	rfc2136: {
-		display_name: 'RFC 2136',
-		package_name: 'certbot-dns-rfc2136',
-		// version_requirement: '', // Official plugin, no version requirement
-		dependencies: '',
-		credentials:  `# Target DNS server
+		display_name:        'RFC 2136',
+		package_name:        'certbot-dns-rfc2136',
+		version_requirement: '==$(certbot --version | grep -Eo \'[0-9](\\.[0-9]+)+\')', // official plugin, use certbot version
+		dependencies:        '',
+		credentials:         `# Target DNS server
 dns_rfc2136_server = 192.0.2.1
 # Target DNS port
 dns_rfc2136_port = 53
@@ -452,11 +452,11 @@ dns_rfc2136_algorithm = HMAC-SHA512`,
 	},
 	//####################################################//
 	route53: {
-		display_name: 'Route 53 (Amazon)',
-		package_name: 'certbot-dns-route53',
-		// version_requirement: '', // Official plugin, no version requirement
-		dependencies: '',
-		credentials:  `[default]
+		display_name:        'Route 53 (Amazon)',
+		package_name:        'certbot-dns-route53',
+		version_requirement: '==$(certbot --version | grep -Eo \'[0-9](\\.[0-9]+)+\')', // official plugin, use certbot version
+		dependencies:        '',
+		credentials:         `[default]
 aws_access_key_id=AKIAIOSFODNN7EXAMPLE
 aws_secret_access_key=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY`,
 		full_plugin_name: 'dns-route53',
@@ -472,6 +472,16 @@ dns_transip_key_file = /etc/letsencrypt/transip-rsa.key`,
 		full_plugin_name: 'dns-transip',
 	},
 	//####################################################//
+	tencentcloud: {
+		display_name:        'Tencent Cloud',
+		package_name:        'certbot-dns-tencentcloud',
+		version_requirement: '~=2.0.0',
+		dependencies:        '',
+		credentials:         `dns_tencentcloud_secret_id  = TENCENT_CLOUD_SECRET_ID
+dns_tencentcloud_secret_key = TENCENT_CLOUD_SECRET_KEY`,
+		full_plugin_name: 'dns-tencentcloud',
+	},
+	//####################################################//
 	vultr: {
 		display_name:        'Vultr',
 		package_name:        'certbot-dns-vultr',