Procházet zdrojové kódy

Refactor certbot plugins install

- Added a script to install every single plugin, used in development and debugging
- Improved certbot plugin install commands
- Adjusted some version for plugins to install properly
- It's noted that some plugins require deps that do not match other plugins,
  however these use cases should be extremely rare
Jamie Curnow před 1 rokem
rodič
revize
db23c9a52f

+ 27 - 37
backend/internal/certificate.js

@@ -9,10 +9,11 @@ const error            = require('../lib/error');
 const utils            = require('../lib/utils');
 const certificateModel = require('../models/certificate');
 const tokenModel       = require('../models/token');
-const dnsPlugins       = require('../global/certbot-dns-plugins');
+const dnsPlugins       = require('../global/certbot-dns-plugins.json');
 const internalAuditLog = require('./audit-log');
 const internalNginx    = require('./nginx');
 const internalHost     = require('./host');
+const certbot          = require('../lib/certbot');
 const archiver         = require('archiver');
 const path             = require('path');
 const { isArray }      = require('lodash');
@@ -849,26 +850,20 @@ const internalCertificate = {
 
 	/**
 	 * @param   {Object}         certificate          the certificate row
-	 * @param   {String}         dns_provider         the dns provider name (key used in `certbot-dns-plugins.js`)
+	 * @param   {String}         dns_provider         the dns provider name (key used in `certbot-dns-plugins.json`)
 	 * @param   {String | null}  credentials          the content of this providers credentials file
-	 * @param   {String}         propagation_seconds  the cloudflare api token
+	 * @param   {String}         propagation_seconds
 	 * @returns {Promise}
 	 */
-	requestLetsEncryptSslWithDnsChallenge: (certificate) => {
-		const dns_plugin = dnsPlugins[certificate.meta.dns_provider];
-
-		if (!dns_plugin) {
-			throw Error(`Unknown DNS provider '${certificate.meta.dns_provider}'`);
-		}
-
-		logger.info(`Requesting Let'sEncrypt certificates via ${dns_plugin.display_name} for Cert #${certificate.id}: ${certificate.domain_names.join(', ')}`);
+	requestLetsEncryptSslWithDnsChallenge: async (certificate) => {
+		await certbot.installPlugin(certificate.meta.dns_provider);
+		const dnsPlugin = dnsPlugins[certificate.meta.dns_provider];
+		logger.info(`Requesting Let'sEncrypt certificates via ${dnsPlugin.name} for Cert #${certificate.id}: ${certificate.domain_names.join(', ')}`);
 
 		const credentialsLocation = '/etc/letsencrypt/credentials/credentials-' + certificate.id;
 		// 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 + '\'';
-		// we call `. /opt/certbot/bin/activate` (`.` is alternative to `source` in dash) to access certbot venv
-		const prepareCmd = '. /opt/certbot/bin/activate && pip install --no-cache-dir ' + dns_plugin.package_name + (dns_plugin.version_requirement || '') + ' ' + dns_plugin.dependencies + ' && deactivate';
 
 		// Whether the plugin has a --<name>-credentials argument
 		const hasConfigArg = certificate.meta.dns_provider !== 'route53';
@@ -881,15 +876,15 @@ const internalCertificate = {
 			'--agree-tos ' +
 			'--email "' + certificate.meta.letsencrypt_email + '" ' +
 			'--domains "' + certificate.domain_names.join(',') + '" ' +
-			'--authenticator ' + dns_plugin.full_plugin_name + ' ' +
+			'--authenticator ' + dnsPlugin.full_plugin_name + ' ' +
 			(
 				hasConfigArg
-					? '--' + dns_plugin.full_plugin_name + '-credentials "' + credentialsLocation + '"'
+					? '--' + dnsPlugin.full_plugin_name + '-credentials "' + credentialsLocation + '"'
 					: ''
 			) +
 			(
 				certificate.meta.propagation_seconds !== undefined
-					? ' --' + dns_plugin.full_plugin_name + '-propagation-seconds ' + certificate.meta.propagation_seconds
+					? ' --' + dnsPlugin.full_plugin_name + '-propagation-seconds ' + certificate.meta.propagation_seconds
 					: ''
 			) +
 			(letsencryptStaging ? ' --staging' : '');
@@ -903,24 +898,19 @@ const internalCertificate = {
 			mainCmd = mainCmd + ' --dns-duckdns-no-txt-restore';
 		}
 
-		logger.info('Command:', `${credentialsCmd} && ${prepareCmd} && ${mainCmd}`);
-
-		return utils.exec(credentialsCmd)
-			.then(() => {
-				return utils.exec(prepareCmd)
-					.then(() => {
-						return utils.exec(mainCmd)
-							.then(async (result) => {
-								logger.info(result);
-								return result;
-							});
-					});
-			}).catch(async (err) => {
-				// Don't fail if file does not exist
-				const delete_credentialsCmd = `rm -f '${credentialsLocation}' || true`;
-				await utils.exec(delete_credentialsCmd);
-				throw err;
-			});
+		logger.info('Command:', `${credentialsCmd} && && ${mainCmd}`);
+
+		try {
+			await utils.exec(credentialsCmd);
+			const result = await utils.exec(mainCmd);
+			logger.info(result);
+			return result;
+		} catch (err) {
+			// Don't fail if file does not exist
+			const delete_credentialsCmd = `rm -f '${credentialsLocation}' || true`;
+			await utils.exec(delete_credentialsCmd);
+			throw err;
+		}
 	},
 
 
@@ -999,13 +989,13 @@ const internalCertificate = {
 	 * @returns {Promise}
 	 */
 	renewLetsEncryptSslWithDnsChallenge: (certificate) => {
-		const dns_plugin = dnsPlugins[certificate.meta.dns_provider];
+		const dnsPlugin = dnsPlugins[certificate.meta.dns_provider];
 
-		if (!dns_plugin) {
+		if (!dnsPlugin) {
 			throw Error(`Unknown DNS provider '${certificate.meta.dns_provider}'`);
 		}
 
-		logger.info(`Renewing Let'sEncrypt certificates via ${dns_plugin.display_name} for Cert #${certificate.id}: ${certificate.domain_names.join(', ')}`);
+		logger.info(`Renewing Let'sEncrypt certificates via ${dnsPlugin.name} for Cert #${certificate.id}: ${certificate.domain_names.join(', ')}`);
 
 		let mainCmd = certbotCommand + ' renew --force-renewal ' +
 			'--config "' + letsencryptConfig + '" ' +

+ 46 - 0
backend/lib/certbot.js

@@ -0,0 +1,46 @@
+const dnsPlugins = require('../global/certbot-dns-plugins.json');
+const utils      = require('./utils');
+const error      = require('./error');
+const logger     = require('../logger').certbot;
+
+// const letsencryptStaging = config.useLetsencryptStaging();
+// const letsencryptConfig  = '/etc/letsencrypt.ini';
+// const certbotCommand     = 'certbot';
+
+// const acmeVersion  = '1.32.0';
+const CERTBOT_VERSION_REPLACEMENT = '$(certbot --version | grep -Eo \'[0-9](\\.[0-9]+)+\')';
+
+const certbot = {
+
+	/**
+	 * Installs a cerbot plugin given the key for the object from
+	 * ../global/certbot-dns-plugins.json
+	 *
+	 * @param   {string}  pluginKey
+	 * @returns {Object}
+	 */
+	installPlugin: async function (pluginKey) {
+		if (typeof dnsPlugins[pluginKey] === 'undefined') {
+			// throw Error(`Certbot plugin ${pluginKey} not found`);
+			throw new error.ItemNotFoundError(pluginKey);
+		}
+
+		const plugin = dnsPlugins[pluginKey];
+		logger.start(`Installing ${pluginKey}...`);
+
+		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)
+			.then((result) => {
+				logger.complete(`Installed ${pluginKey}`);
+				return result;
+			})
+			.catch((err) => {
+				throw err;
+			});
+	},
+};
+
+module.exports = certbot;

+ 10 - 1
backend/lib/error.js

@@ -82,7 +82,16 @@ module.exports = {
 		this.message  = message;
 		this.public   = false;
 		this.status   = 400;
-	}
+	},
+
+	CommandError: function (stdErr, code, previous) {
+		Error.captureStackTrace(this, this.constructor);
+		this.name     = this.constructor.name;
+		this.previous = previous;
+		this.message  = stdErr;
+		this.code     = code;
+		this.public   = false;
+	},
 };
 
 _.forEach(module.exports, function (error) {

+ 16 - 11
backend/lib/utils.js

@@ -3,23 +3,27 @@ const exec       = require('child_process').exec;
 const execFile   = require('child_process').execFile;
 const { Liquid } = require('liquidjs');
 const logger     = require('../logger').global;
+const error      = require('./error');
 
 module.exports = {
 
-	/**
-	 * @param   {String} cmd
-	 * @returns {Promise}
-	 */
-	exec: function (cmd) {
-		return new Promise((resolve, reject) => {
-			exec(cmd, function (err, stdout, /*stderr*/) {
-				if (err && typeof err === 'object') {
-					reject(err);
+	exec: async function(cmd, options = {}) {
+		logger.debug('CMD:', cmd);
+
+		const { stdout, stderr } = await new Promise((resolve, reject) => {
+			const child = exec(cmd, options, (isError, stdout, stderr) => {
+				if (isError) {
+					reject(new error.CommandError(stderr, isError));
 				} else {
-					resolve(stdout.trim());
+					resolve({ stdout, stderr });
 				}
 			});
+
+			child.on('error', (e) => {
+				reject(new error.CommandError(stderr, 1, e));
+			});
 		});
+		return stdout;
 	},
 
 	/**
@@ -28,7 +32,8 @@ module.exports = {
 	 * @returns {Promise}
 	 */
 	execFile: function (cmd, args) {
-		logger.debug('CMD: ' + cmd + ' ' + (args ? args.join(' ') : ''));
+		// logger.debug('CMD: ' + cmd + ' ' + (args ? args.join(' ') : ''));
+
 		return new Promise((resolve, reject) => {
 			execFile(cmd, args, function (err, stdout, /*stderr*/) {
 				if (err && typeof err === 'object') {

+ 1 - 0
backend/logger.js

@@ -7,6 +7,7 @@ module.exports = {
 	access:    new Signale({scope: 'Access   '}),
 	nginx:     new Signale({scope: 'Nginx    '}),
 	ssl:       new Signale({scope: 'SSL      '}),
+	certbot:   new Signale({scope: 'Certbot  '}),
 	import:    new Signale({scope: 'Importer '}),
 	setup:     new Signale({scope: 'Setup    '}),
 	ip_ranges: new Signale({scope: 'IP Ranges'})

+ 49 - 0
backend/scripts/install-certbot-plugins

@@ -0,0 +1,49 @@
+#!/usr/bin/node
+
+// Usage:
+//   Install all plugins defined in `certbot-dns-plugins.json`:
+//    ./install-certbot-plugins
+//   Install one or more specific plugins:
+//    ./install-certbot-plugins route53 cloudflare
+//
+// Usage with a running docker container:
+//    docker exec npm_core /command/s6-setuidgid 1000:1000 bash -c "/app/scripts/install-certbot-plugins"
+//
+
+const dnsPlugins = require('../global/certbot-dns-plugins.json');
+const certbot    = require('../lib/certbot');
+const logger     = require('../logger').certbot;
+const batchflow  = require('batchflow');
+
+let hasErrors      = false;
+let failingPlugins = [];
+
+let pluginKeys = Object.keys(dnsPlugins);
+if (process.argv.length > 2) {
+	pluginKeys = process.argv.slice(2);
+}
+
+batchflow(pluginKeys).sequential()
+	.each((i, pluginKey, next) => {
+		certbot.installPlugin(pluginKey)
+			.then(() => {
+				next();
+			})
+			.catch((err) => {
+				hasErrors = true;
+				failingPlugins.push(pluginKey);
+				next(err);
+			});
+	})
+	.error((err) => {
+		logger.error(err.message);
+	})
+	.end(() => {
+		if (hasErrors) {
+			logger.error('Some plugins failed to install. Please check the logs above. Failing plugins: ' + '\n - ' + failingPlugins.join('\n - '));
+			process.exit(1);
+		} else {
+			logger.complete('Plugins installed successfully');
+			process.exit(0);
+		}
+	});

+ 1 - 0
docker/rootfs/etc/s6-overlay/s6-rc.d/prepare/30-ownership.sh

@@ -24,4 +24,5 @@ chown -R "$PUID:$PGID" /etc/nginx/nginx.conf
 chown -R "$PUID:$PGID" /etc/nginx/conf.d
 
 # Prevents errors when installing python certbot plugins when non-root
+chown "$PUID:$PGID" /opt/certbot /opt/certbot/bin
 chown -R "$PUID:$PGID" /opt/certbot/lib/python*/site-packages

+ 24 - 24
frontend/js/app/nginx/certificates/form.ejs

@@ -22,7 +22,7 @@
                         <div class="mb-3 test-domains-container">
                             <button type="button" class="btn btn-secondary test-domains col-sm-12"><%- i18n('certificates', 'test-reachability') %></button>
                             <div class="text-secondary small">
-                                <i class="fe fe-info"></i> 
+                                <i class="fe fe-info"></i>
                                 <%- i18n('certificates', 'reachability-info') %>
                             </div>
                         </div>
@@ -38,11 +38,11 @@
                     <div class="col-sm-12 col-md-12">
                         <div class="form-group">
                             <label class="custom-switch">
-                                <input 
-                                    type="checkbox" 
-                                    class="custom-switch-input" 
-                                    name="meta[dns_challenge]" 
-                                    value="1" 
+                                <input
+                                    type="checkbox"
+                                    class="custom-switch-input"
+                                    name="meta[dns_challenge]"
+                                    value="1"
                                     <%- getUseDnsChallenge() ? 'checked' : '' %>
                                 >
                                 <span class="custom-switch-indicator"></span>
@@ -59,22 +59,22 @@
                                 <div class="col-sm-12 col-md-12">
                                     <div class="form-group">
                                         <label class="form-label"><%- i18n('ssl', 'dns-provider') %> <span class="form-required">*</span></label>
-                                        <select 
-                                            name="meta[dns_provider]" 
+                                        <select
+                                            name="meta[dns_provider]"
                                             id="dns_provider"
                                             class="form-control custom-select"
                                         >
-                                            <option 
-                                                value="" 
-                                                disabled 
+                                            <option
+                                                value=""
+                                                disabled
                                                 hidden
                                                 <%- getDnsProvider() === null ? 'selected' : '' %>
                                             >Please Choose...</option>
                                             <% _.each(dns_plugins, function(plugin_info, plugin_name){ %>
-                                            <option 
+                                            <option
                                                 value="<%- plugin_name %>"
                                                 <%- getDnsProvider() === plugin_name ? 'selected' : '' %>
-                                            ><%- plugin_info.display_name %></option>
+                                            ><%- plugin_info.name %></option>
                                             <% }); %>
                                         </select>
                                     </div>
@@ -86,17 +86,17 @@
                                 <div class="col-sm-12 col-md-12">
                                     <div class="form-group">
                                         <label class="form-label"><%- i18n('ssl', 'credentials-file-content') %> <span class="form-required">*</span></label>
-                                        <textarea 
-                                            name="meta[dns_provider_credentials]" 
-                                            class="form-control text-monospace" 
-                                            id="dns_provider_credentials" 
+                                        <textarea
+                                            name="meta[dns_provider_credentials]"
+                                            class="form-control text-monospace"
+                                            id="dns_provider_credentials"
                                         ><%- getDnsProviderCredentials() %></textarea>
                                         <div class="text-secondary small">
-                                            <i class="fe fe-info"></i> 
+                                            <i class="fe fe-info"></i>
                                             <%= i18n('ssl', 'credentials-file-content-info') %>
                                         </div>
                                         <div class="text-red small">
-                                            <i class="fe fe-alert-triangle"></i> 
+                                            <i class="fe fe-alert-triangle"></i>
                                             <%= i18n('ssl', 'stored-as-plaintext-info') %>
                                         </div>
                                     </div>
@@ -108,16 +108,16 @@
                                 <div class="col-sm-12 col-md-12">
                                     <div class="form-group mb-0">
                                         <label class="form-label"><%- i18n('ssl', 'propagation-seconds') %></label>
-                                        <input 
+                                        <input
                                             type="number"
                                             min="0"
-                                            name="meta[propagation_seconds]" 
-                                            class="form-control" 
-                                            id="propagation_seconds" 
+                                            name="meta[propagation_seconds]"
+                                            class="form-control"
+                                            id="propagation_seconds"
                                             value="<%- getPropagationSeconds() %>"
                                         >
                                         <div class="text-secondary small">
-                                            <i class="fe fe-info"></i> 
+                                            <i class="fe fe-info"></i>
                                             <%= i18n('ssl', 'propagation-seconds-info') %>
                                         </div>
                                     </div>

+ 8 - 8
frontend/js/app/nginx/certificates/form.js

@@ -11,7 +11,7 @@ require('selectize');
 
 function sortProvidersAlphabetically(obj) {
     return Object.entries(obj)
-        .sort((a,b) => a[1].display_name.toLowerCase() > b[1].display_name.toLowerCase())
+        .sort((a,b) => a[1].name.toLowerCase() > b[1].name.toLowerCase())
         .reduce((result, entry) => {
             result[entry[0]] = entry[1];
             return result;
@@ -47,7 +47,7 @@ module.exports = Mn.View.extend({
         other_intermediate_certificate:       '#other_intermediate_certificate',
         other_intermediate_certificate_label: '#other_intermediate_certificate_label'
     },
-    
+
     events: {
         'change @ui.dns_challenge_switch': function () {
             const checked = this.ui.dns_challenge_switch.prop('checked');
@@ -63,7 +63,7 @@ module.exports = Mn.View.extend({
                 this.ui.dns_provider.prop('required', false);
                 this.ui.dns_provider_credentials.prop('required', false);
                 this.ui.dns_challenge_content.hide();
-                this.ui.test_domains_container.show();            
+                this.ui.test_domains_container.show();
             }
         },
 
@@ -75,10 +75,10 @@ module.exports = Mn.View.extend({
                 this.ui.credentials_file_content.show();
             } else {
                 this.ui.dns_provider_credentials.prop('required', false);
-                this.ui.credentials_file_content.hide();                
+                this.ui.credentials_file_content.hide();
             }
         },
-        
+
         'click @ui.save': function (e) {
             e.preventDefault();
             this.ui.le_error_info.hide();
@@ -97,7 +97,7 @@ module.exports = Mn.View.extend({
                 if (typeof data.meta === 'undefined') data.meta = {};
 
                 let domain_err = false;
-                if (!data.meta.dns_challenge) {                
+                if (!data.meta.dns_challenge) {
                     data.domain_names.split(',').map(function (name) {
                         if (name.match(/\*/im)) {
                             domain_err = true;
@@ -119,7 +119,7 @@ module.exports = Mn.View.extend({
                     data.meta.dns_provider_credentials = undefined;
                     data.meta.propagation_seconds = undefined;
                 } else {
-                    if(data.meta.propagation_seconds === '') data.meta.propagation_seconds = undefined; 
+                    if(data.meta.propagation_seconds === '') data.meta.propagation_seconds = undefined;
                 }
 
                 if (typeof data.domain_names === 'string' && data.domain_names) {
@@ -275,7 +275,7 @@ module.exports = Mn.View.extend({
             createFilter: /^(?:\*\.)?(?:[^.*]+\.?)+[^.]$/
         });
         this.ui.dns_challenge_content.hide();
-        this.ui.credentials_file_content.hide(); 
+        this.ui.credentials_file_content.hide();
         this.ui.loader_content.hide();
         this.ui.le_error_info.hide();
         if (this.ui.domain_names[0]) {

+ 2 - 2
frontend/js/app/nginx/certificates/list/item.ejs

@@ -28,7 +28,7 @@
     </div>
 </td>
 <td>
-    <%- i18n('ssl', provider) %><% if (meta.dns_provider) { %> - <%- dns_providers[meta.dns_provider].display_name %><% } %>
+    <%- i18n('ssl', provider) %><% if (meta.dns_provider) { %> - <%- dns_providers[meta.dns_provider].name %><% } %>
 </td>
 <td class="<%- isExpired() ? 'text-danger' : '' %>">
     <%- formatDbDate(expires_on, 'Do MMMM YYYY, h:mm a') %>
@@ -51,4 +51,4 @@
         </div>
     </div>
 </td>
-<% } %>
+<% } %>

+ 23 - 23
frontend/js/app/nginx/dead/form.ejs

@@ -78,11 +78,11 @@
                         <div class="col-sm-12 col-md-12 letsencrypt">
                             <div class="form-group">
                                 <label class="custom-switch">
-                                    <input 
-                                        type="checkbox" 
-                                        class="custom-switch-input" 
-                                        name="meta[dns_challenge]" 
-                                        value="1" 
+                                    <input
+                                        type="checkbox"
+                                        class="custom-switch-input"
+                                        name="meta[dns_challenge]"
+                                        value="1"
                                         <%- getUseDnsChallenge() ? 'checked' : '' %>
                                     >
                                     <span class="custom-switch-indicator"></span>
@@ -99,22 +99,22 @@
                                     <div class="col-sm-12 col-md-12">
                                         <div class="form-group">
                                             <label class="form-label"><%- i18n('ssl', 'dns-provider') %> <span class="form-required">*</span></label>
-                                            <select 
-                                                name="meta[dns_provider]" 
+                                            <select
+                                                name="meta[dns_provider]"
                                                 id="dns_provider"
                                                 class="form-control custom-select"
                                             >
-                                                <option 
-                                                    value="" 
-                                                    disabled 
+                                                <option
+                                                    value=""
+                                                    disabled
                                                     hidden
                                                     <%- getDnsProvider() === null ? 'selected' : '' %>
                                                 >Please Choose...</option>
                                                 <% _.each(dns_plugins, function(plugin_info, plugin_name){ %>
-                                                <option 
+                                                <option
                                                     value="<%- plugin_name %>"
                                                     <%- getDnsProvider() === plugin_name ? 'selected' : '' %>
-                                                ><%- plugin_info.display_name %></option>
+                                                ><%- plugin_info.name %></option>
                                                 <% }); %>
                                             </select>
                                         </div>
@@ -126,17 +126,17 @@
                                     <div class="col-sm-12 col-md-12">
                                         <div class="form-group">
                                             <label class="form-label"><%- i18n('ssl', 'credentials-file-content') %> <span class="form-required">*</span></label>
-                                            <textarea 
-                                                name="meta[dns_provider_credentials]" 
-                                                class="form-control text-monospace" 
-                                                id="dns_provider_credentials" 
+                                            <textarea
+                                                name="meta[dns_provider_credentials]"
+                                                class="form-control text-monospace"
+                                                id="dns_provider_credentials"
                                             ><%- getDnsProviderCredentials() %></textarea>
                                             <div class="text-secondary small">
-                                                <i class="fe fe-info"></i> 
+                                                <i class="fe fe-info"></i>
                                                 <%= i18n('ssl', 'credentials-file-content-info') %>
                                             </div>
                                             <div class="text-red small">
-                                                <i class="fe fe-alert-triangle"></i> 
+                                                <i class="fe fe-alert-triangle"></i>
                                                 <%= i18n('ssl', 'stored-as-plaintext-info') %>
                                             </div>
                                         </div>
@@ -148,16 +148,16 @@
                                     <div class="col-sm-12 col-md-12">
                                         <div class="form-group mb-0">
                                             <label class="form-label"><%- i18n('ssl', 'propagation-seconds') %></label>
-                                            <input 
+                                            <input
                                                 type="number"
                                                 min="0"
-                                                name="meta[propagation_seconds]" 
-                                                class="form-control" 
-                                                id="propagation_seconds" 
+                                                name="meta[propagation_seconds]"
+                                                class="form-control"
+                                                id="propagation_seconds"
                                                 value="<%- getPropagationSeconds() %>"
                                             >
                                             <div class="text-secondary small">
-                                                <i class="fe fe-info"></i> 
+                                                <i class="fe fe-info"></i>
                                                 <%= i18n('ssl', 'propagation-seconds-info') %>
                                             </div>
                                         </div>

+ 23 - 23
frontend/js/app/nginx/proxy/form.ejs

@@ -146,11 +146,11 @@
                         <div class="col-sm-12 col-md-12 letsencrypt">
                             <div class="form-group">
                                 <label class="custom-switch">
-                                    <input 
-                                        type="checkbox" 
-                                        class="custom-switch-input" 
-                                        name="meta[dns_challenge]" 
-                                        value="1" 
+                                    <input
+                                        type="checkbox"
+                                        class="custom-switch-input"
+                                        name="meta[dns_challenge]"
+                                        value="1"
                                         <%- getUseDnsChallenge() ? 'checked' : '' %>
                                     >
                                     <span class="custom-switch-indicator"></span>
@@ -167,22 +167,22 @@
                                     <div class="col-sm-12 col-md-12">
                                         <div class="form-group">
                                             <label class="form-label"><%- i18n('ssl', 'dns-provider') %> <span class="form-required">*</span></label>
-                                            <select 
-                                                name="meta[dns_provider]" 
+                                            <select
+                                                name="meta[dns_provider]"
                                                 id="dns_provider"
                                                 class="form-control custom-select"
                                             >
-                                                <option 
-                                                    value="" 
-                                                    disabled 
+                                                <option
+                                                    value=""
+                                                    disabled
                                                     hidden
                                                     <%- getDnsProvider() === null ? 'selected' : '' %>
                                                 >Please Choose...</option>
                                                 <% _.each(dns_plugins, function(plugin_info, plugin_name){ %>
-                                                <option 
+                                                <option
                                                     value="<%- plugin_name %>"
                                                     <%- getDnsProvider() === plugin_name ? 'selected' : '' %>
-                                                ><%- plugin_info.display_name %></option>
+                                                ><%- plugin_info.name %></option>
                                                 <% }); %>
                                             </select>
                                         </div>
@@ -194,17 +194,17 @@
                                     <div class="col-sm-12 col-md-12">
                                         <div class="form-group">
                                             <label class="form-label"><%- i18n('ssl', 'credentials-file-content') %> <span class="form-required">*</span></label>
-                                            <textarea 
-                                                name="meta[dns_provider_credentials]" 
-                                                class="form-control text-monospace" 
-                                                id="dns_provider_credentials" 
+                                            <textarea
+                                                name="meta[dns_provider_credentials]"
+                                                class="form-control text-monospace"
+                                                id="dns_provider_credentials"
                                             ><%- getDnsProviderCredentials() %></textarea>
                                             <div class="text-secondary small">
-                                                <i class="fe fe-info"></i> 
+                                                <i class="fe fe-info"></i>
                                                 <%= i18n('ssl', 'credentials-file-content-info') %>
                                             </div>
                                             <div class="text-red small">
-                                                <i class="fe fe-alert-triangle"></i> 
+                                                <i class="fe fe-alert-triangle"></i>
                                                 <%= i18n('ssl', 'stored-as-plaintext-info') %>
                                             </div>
                                         </div>
@@ -216,16 +216,16 @@
                                     <div class="col-sm-12 col-md-12">
                                         <div class="form-group mb-0">
                                             <label class="form-label"><%- i18n('ssl', 'propagation-seconds') %></label>
-                                            <input 
+                                            <input
                                                 type="number"
                                                 min="0"
-                                                name="meta[propagation_seconds]" 
-                                                class="form-control" 
-                                                id="propagation_seconds" 
+                                                name="meta[propagation_seconds]"
+                                                class="form-control"
+                                                id="propagation_seconds"
                                                 value="<%- getPropagationSeconds() %>"
                                             >
                                             <div class="text-secondary small">
-                                                <i class="fe fe-info"></i> 
+                                                <i class="fe fe-info"></i>
                                                 <%= i18n('ssl', 'propagation-seconds-info') %>
                                             </div>
                                         </div>

+ 23 - 23
frontend/js/app/nginx/redirection/form.ejs

@@ -125,11 +125,11 @@
                         <div class="col-sm-12 col-md-12 letsencrypt">
                             <div class="form-group">
                                 <label class="custom-switch">
-                                    <input 
-                                        type="checkbox" 
-                                        class="custom-switch-input" 
-                                        name="meta[dns_challenge]" 
-                                        value="1" 
+                                    <input
+                                        type="checkbox"
+                                        class="custom-switch-input"
+                                        name="meta[dns_challenge]"
+                                        value="1"
                                         <%- getUseDnsChallenge() ? 'checked' : '' %>
                                     >
                                     <span class="custom-switch-indicator"></span>
@@ -146,22 +146,22 @@
                                     <div class="col-sm-12 col-md-12">
                                         <div class="form-group">
                                             <label class="form-label"><%- i18n('ssl', 'dns-provider') %> <span class="form-required">*</span></label>
-                                            <select 
-                                                name="meta[dns_provider]" 
+                                            <select
+                                                name="meta[dns_provider]"
                                                 id="dns_provider"
                                                 class="form-control custom-select"
                                             >
-                                                <option 
-                                                    value="" 
-                                                    disabled 
+                                                <option
+                                                    value=""
+                                                    disabled
                                                     hidden
                                                     <%- getDnsProvider() === null ? 'selected' : '' %>
                                                 >Please Choose...</option>
                                                 <% _.each(dns_plugins, function(plugin_info, plugin_name){ %>
-                                                <option 
+                                                <option
                                                     value="<%- plugin_name %>"
                                                     <%- getDnsProvider() === plugin_name ? 'selected' : '' %>
-                                                ><%- plugin_info.display_name %></option>
+                                                ><%- plugin_info.name %></option>
                                                 <% }); %>
                                             </select>
                                         </div>
@@ -173,17 +173,17 @@
                                     <div class="col-sm-12 col-md-12">
                                         <div class="form-group">
                                             <label class="form-label"><%- i18n('ssl', 'credentials-file-content') %> <span class="form-required">*</span></label>
-                                            <textarea 
-                                                name="meta[dns_provider_credentials]" 
-                                                class="form-control text-monospace" 
-                                                id="dns_provider_credentials" 
+                                            <textarea
+                                                name="meta[dns_provider_credentials]"
+                                                class="form-control text-monospace"
+                                                id="dns_provider_credentials"
                                             ><%- getDnsProviderCredentials() %></textarea>
                                             <div class="text-secondary small">
-                                                <i class="fe fe-info"></i> 
+                                                <i class="fe fe-info"></i>
                                                 <%= i18n('ssl', 'credentials-file-content-info') %>
                                             </div>
                                             <div class="text-red small">
-                                                <i class="fe fe-alert-triangle"></i> 
+                                                <i class="fe fe-alert-triangle"></i>
                                                 <%= i18n('ssl', 'stored-as-plaintext-info') %>
                                             </div>
                                         </div>
@@ -195,16 +195,16 @@
                                     <div class="col-sm-12 col-md-12">
                                         <div class="form-group mb-0">
                                             <label class="form-label"><%- i18n('ssl', 'propagation-seconds') %></label>
-                                            <input 
+                                            <input
                                                 type="number"
                                                 min="0"
-                                                name="meta[propagation_seconds]" 
-                                                class="form-control" 
-                                                id="propagation_seconds" 
+                                                name="meta[propagation_seconds]"
+                                                class="form-control"
+                                                id="propagation_seconds"
                                                 value="<%- getPropagationSeconds() %>"
                                             >
                                             <div class="text-secondary small">
-                                                <i class="fe fe-info"></i> 
+                                                <i class="fe fe-info"></i>
                                                 <%= i18n('ssl', 'propagation-seconds-info') %>
                                             </div>
                                         </div>

+ 21 - 0
global/README.md

@@ -0,0 +1,21 @@
+# certbot-dns-plugins
+
+This file contains info about available Certbot DNS plugins.
+This only works for plugins which use the standard argument structure, so:
+--authenticator <plugin-name> --<plugin-name>-credentials <FILE> --<plugin-name>-propagation-seconds <number>
+
+File Structure:
+
+```json
+{
+  "cloudflare": {
+    "display_name": "Name displayed to the user",
+    "package_name": "Package name in PyPi repo",
+    "version_requirement": "Optional package version requirements (e.g. ==1.3 or >=1.2,<2.0, see https://www.python.org/dev/peps/pep-0440/#version-specifiers)",
+    "dependencies": "Additional dependencies, space separated (as you would pass it to pip install)",
+    "credentials": "Template of the credentials file",
+    "full_plugin_name": "The full plugin name as used in the commandline with certbot, e.g. 'dns-njalla'"
+  },
+  ...
+}
+```

+ 0 - 615
global/certbot-dns-plugins.js

@@ -1,615 +0,0 @@
-/**
- * This file contains info about available Certbot DNS plugins.
- * This only works for plugins which use the standard argument structure, so:
- * --authenticator <plugin-name> --<plugin-name>-credentials <FILE> --<plugin-name>-propagation-seconds <number>
- *
- * File Structure:
- *
- *  {
- *    cloudflare: {
- *      display_name: "Name displayed to the user",
- *      package_name: "Package name in PyPi repo",
- *      version_requirement: "Optional package version requirements (e.g. ==1.3 or >=1.2,<2.0, see https://www.python.org/dev/peps/pep-0440/#version-specifiers)",
- *      dependencies: "Additional dependencies, space separated (as you would pass it to pip install)",
- *      credentials: `Template of the credentials file`,
- *      full_plugin_name: "The full plugin name as used in the commandline with certbot, e.g. 'dns-njalla'",
- *    },
- *    ...
- *  }
- *
- */
-
-module.exports = {
-	//####################################################//
-	acmedns: {
-		display_name:        'ACME-DNS',
-		package_name:        'certbot-dns-acmedns',
-		version_requirement: '~=0.1.0',
-		dependencies:        '',
-		credentials:         `dns_acmedns_api_url = http://acmedns-server/
-dns_acmedns_registration_file = /data/acme-registration.json`,
-		full_plugin_name: 'dns-acmedns',
-	},
-	aliyun: {
-		display_name:        'Aliyun',
-		package_name:        'certbot-dns-aliyun',
-		version_requirement: '~=0.38.1',
-		dependencies:        '',
-		credentials:         `dns_aliyun_access_key = 12345678
-dns_aliyun_access_key_secret = 1234567890abcdef1234567890abcdef`,
-		full_plugin_name: 'dns-aliyun',
-	},
-	//####################################################//
-	azure: {
-		display_name:        'Azure',
-		package_name:        'certbot-dns-azure',
-		version_requirement: '~=1.2.0',
-		dependencies:        '',
-		credentials:         `# This plugin supported API authentication using either Service Principals or utilizing a Managed Identity assigned to the virtual machine.
-# Regardless which authentication method used, the identity will need the “DNS Zone Contributor” role assigned to it.
-# As multiple Azure DNS Zones in multiple resource groups can exist, the config file needs a mapping of zone to resource group ID. Multiple zones -> ID mappings can be listed by using the key dns_azure_zoneX where X is a unique number. At least 1 zone mapping is required.
-
-# Using a service principal (option 1)
-dns_azure_sp_client_id = 912ce44a-0156-4669-ae22-c16a17d34ca5
-dns_azure_sp_client_secret = E-xqXU83Y-jzTI6xe9fs2YC~mck3ZzUih9
-dns_azure_tenant_id = ed1090f3-ab18-4b12-816c-599af8a88cf7
-
-# Using used assigned MSI (option 2)
-# dns_azure_msi_client_id = 912ce44a-0156-4669-ae22-c16a17d34ca5
-
-# Using system assigned MSI (option 3)
-# dns_azure_msi_system_assigned = true
-
-# Zones (at least one always required)
-dns_azure_zone1 = example.com:/subscriptions/c135abce-d87d-48df-936c-15596c6968a5/resourceGroups/dns1
-dns_azure_zone2 = example.org:/subscriptions/99800903-fb14-4992-9aff-12eaf2744622/resourceGroups/dns2`,
-		full_plugin_name: 'dns-azure',
-	},
-	//####################################################//
-	bunny: {
-		display_name:        'bunny.net',
-		package_name:        'certbot-dns-bunny',
-		version_requirement: '~=0.0.9',
-		dependencies:        '',
-		credentials:         `# Bunny API token used by Certbot (see https://dash.bunny.net/account/settings)
-dns_bunny_api_key = xxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx`,
-		full_plugin_name: 'dns-bunny',
-	},
-	//####################################################//
-	cloudflare: {
-		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',
-	},
-	//####################################################//
-	cloudns: {
-		display_name:        'ClouDNS',
-		package_name:        'certbot-dns-cloudns',
-		version_requirement: '~=0.4.0',
-		dependencies:        '',
-		credentials:         `# Target user ID (see https://www.cloudns.net/api-settings/)
-	dns_cloudns_auth_id=1234
-	# Alternatively, one of the following two options can be set:
-	# dns_cloudns_sub_auth_id=1234
-	# dns_cloudns_sub_auth_user=foobar
-
-	# API password
-	dns_cloudns_auth_password=password1`,
-		full_plugin_name: 'dns-cloudns',
-	},
-	//####################################################//
-	cloudxns: {
-		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',
-	},
-	//####################################################//
-	constellix: {
-		display_name:        'Constellix',
-		package_name:        'certbot-dns-constellix',
-		version_requirement: '~=0.2.1',
-		dependencies:        '',
-		credentials:         `dns_constellix_apikey = 5fb4e76f-ac91-43e5-f982458bc595
-dns_constellix_secretkey = 47d99fd0-32e7-4e07-85b46d08e70b
-dns_constellix_endpoint = https://api.dns.constellix.com/v1`,
-		full_plugin_name: 'dns-constellix',
-	},
-	//####################################################//
-	corenetworks: {
-		display_name:        'Core Networks',
-		package_name:        'certbot-dns-corenetworks',
-		version_requirement: '~=0.1.4',
-		dependencies:        '',
-		credentials:         `dns_corenetworks_username = asaHB12r
-dns_corenetworks_password = secure_password`,
-		full_plugin_name: 'dns-corenetworks',
-	},
-	//####################################################//
-	cpanel: {
-		display_name:        'cPanel',
-		package_name:        'certbot-dns-cpanel',
-		version_requirement: '~=0.2.2',
-		dependencies:        '',
-		credentials:         `cpanel_url = https://cpanel.example.com:2083
-cpanel_username = user
-cpanel_password = hunter2`,
-		full_plugin_name: 'cpanel',
-	},
-	//####################################################//
-	desec: {
-		display_name:        'deSEC',
-		package_name:        'certbot-dns-desec',
-		version_requirement: '~=1.2.1',
-		dependencies:        '',
-		credentials:         `dns_desec_token = YOUR_DESEC_API_TOKEN
-dns_desec_endpoint = https://desec.io/api/v1/`,
-		full_plugin_name: 'dns-desec',
-	},
-	//####################################################//
-	duckdns: {
-		display_name:        'DuckDNS',
-		package_name:        'certbot-dns-duckdns',
-		version_requirement: '~=0.9',
-		dependencies:        '',
-		credentials:         'dns_duckdns_token=your-duckdns-token',
-		full_plugin_name:    'dns-duckdns',
-	},
-	//####################################################//
-	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: {
-		display_name:        'DirectAdmin',
-		package_name:        'certbot-dns-directadmin',
-		version_requirement: '~=0.0.23',
-		dependencies:        '',
-		credentials:         `directadmin_url = https://my.directadminserver.com:2222
-directadmin_username = username
-directadmin_password = aSuperStrongPassword`,
-		full_plugin_name: 'directadmin',
-	},
-	//####################################################//
-	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: '==$(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',
-	},
-	//####################################################//
-	dnspod: {
-		display_name:        'DNSPod',
-		package_name:        'certbot-dns-dnspod',
-		version_requirement: '~=0.1.0',
-		dependencies:        '',
-		credentials:         `dns_dnspod_email = "[email protected]"
-dns_dnspod_api_token = "id,key"`,
-		full_plugin_name: 'dns-dnspod',
-	},
-	//####################################################//
-	domainoffensive: {
-		display_name:        'DomainOffensive (do.de)',
-		package_name:        'certbot-dns-do',
-		version_requirement: '~=0.31.0',
-		dependencies:        '',
-		credentials:         'dns_do_api_token = YOUR_DO_DE_AUTH_TOKEN',
-		full_plugin_name:    'dns-do',
-	},
-	//####################################################//
-	domeneshop: {
-		display_name:        'Domeneshop',
-		package_name:        'certbot-dns-domeneshop',
-		version_requirement: '~=0.2.8',
-		dependencies:        '',
-		credentials:         `dns_domeneshop_client_token=YOUR_DOMENESHOP_CLIENT_TOKEN
-dns_domeneshop_client_secret=YOUR_DOMENESHOP_CLIENT_SECRET`,
-		full_plugin_name: 'dns-domeneshop',
-	},
-	//####################################################//
-	dynu: {
-		display_name:        'Dynu',
-		package_name:        'certbot-dns-dynu',
-		version_requirement: '~=0.0.1',
-		dependencies:        '',
-		credentials:         'dns_dynu_auth_token = YOUR_DYNU_AUTH_TOKEN',
-		full_plugin_name:    'dns-dynu',
-	},
-	//####################################################//
-	eurodns: {
-		display_name:        'EuroDNS',
-		package_name:        'certbot-dns-eurodns',
-		version_requirement: '~=0.0.4',
-		dependencies:        '',
-		credentials:         `dns_eurodns_applicationId = myuser
-dns_eurodns_apiKey = mysecretpassword
-dns_eurodns_endpoint = https://rest-api.eurodns.com/user-api-gateway/proxy`,
-		full_plugin_name: 'dns-eurodns',
-	},
-	//####################################################//
-	gandi: {
-		display_name:        'Gandi Live DNS',
-		package_name:        'certbot_plugin_gandi',
-		version_requirement: '~=1.5.0',
-		dependencies:        '',
-		credentials:         `# Gandi personal access token
-dns_gandi_token=PERSONAL_ACCESS_TOKEN`,
-		full_plugin_name: 'dns-gandi',
-	},
-	//####################################################//
-	godaddy: {
-		display_name:        'GoDaddy',
-		package_name:        'certbot-dns-godaddy',
-		version_requirement: '~=0.2.0',
-		dependencies:        '',
-		credentials:         `dns_godaddy_secret = 0123456789abcdef0123456789abcdef01234567
-dns_godaddy_key = abcdef0123456789abcdef01234567abcdef0123`,
-		full_plugin_name: 'dns-godaddy',
-	},
-	//####################################################//
-	google: {
-		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",
-...
-}`,
-		full_plugin_name: 'dns-google',
-	},
-	//####################################################//
-	googledomains: {
-		display_name:        'GoogleDomainsDNS',
-		package_name:        'certbot-dns-google-domains',
-		version_requirement: '~=0.1.5',
-		dependencies:        '',
-		credentials:         `dns_google_domains_access_token = 0123456789abcdef0123456789abcdef01234567
-dns_google_domains_zone = "example.com"`,
-		full_plugin_name: 'dns-google-domains',
-	},
-	//####################################################//
-	he: {
-		display_name:        'Hurricane Electric',
-		package_name:        'certbot-dns-he',
-		version_requirement: '~=1.0.0',
-		dependencies:        '',
-		credentials:         `dns_he_user = Me
-dns_he_pass = my HE password`,
-		full_plugin_name: 'dns-he',
-	},
-	//####################################################//
-	hetzner: {
-		display_name:        'Hetzner',
-		package_name:        'certbot-dns-hetzner',
-		version_requirement: '~=1.0.4',
-		dependencies:        '',
-		credentials:         'dns_hetzner_api_token = 0123456789abcdef0123456789abcdef',
-		full_plugin_name:    'dns-hetzner',
-	},
-	//####################################################//
-	infomaniak: {
-		display_name:        'Infomaniak',
-		package_name:        'certbot-dns-infomaniak',
-		version_requirement: '~=0.1.12',
-		dependencies:        '',
-		credentials:         'dns_infomaniak_token = XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
-		full_plugin_name:    'dns-infomaniak',
-	},
-	//####################################################//
-	inwx: {
-		display_name:        'INWX',
-		package_name:        'certbot-dns-inwx',
-		version_requirement: '~=2.1.2',
-		dependencies:        '',
-		credentials:         `dns_inwx_url = https://api.domrobot.com/xmlrpc/
-dns_inwx_username = your_username
-dns_inwx_password = your_password
-dns_inwx_shared_secret = your_shared_secret optional`,
-		full_plugin_name: 'dns-inwx',
-	},
-	//####################################################//
-	ionos: {
-		display_name:        'IONOS',
-		package_name:        'certbot-dns-ionos',
-		version_requirement: '==2022.11.24',
-		dependencies:        '',
-		credentials:         `dns_ionos_prefix = myapikeyprefix
-dns_ionos_secret = verysecureapikeysecret
-dns_ionos_endpoint = https://api.hosting.ionos.com`,
-		full_plugin_name: 'dns-ionos',
-	},
-	//####################################################//
-	ispconfig: {
-		display_name:        'ISPConfig',
-		package_name:        'certbot-dns-ispconfig',
-		version_requirement: '~=0.2.0',
-		dependencies:        '',
-		credentials:         `dns_ispconfig_username = myremoteuser
-dns_ispconfig_password = verysecureremoteuserpassword
-dns_ispconfig_endpoint = https://localhost:8080`,
-		full_plugin_name: 'dns-ispconfig',
-	},
-	//####################################################//
-	isset: {
-		display_name:        'Isset',
-		package_name:        'certbot-dns-isset',
-		version_requirement: '~=0.0.3',
-		dependencies:        '',
-		credentials:         `dns_isset_endpoint="https://customer.isset.net/api"
-dns_isset_token="<token>"`,
-		full_plugin_name: 'dns-isset',
-	},
-	joker: {
-		display_name:        'Joker',
-		package_name:        'certbot-dns-joker',
-		version_requirement: '~=1.1.0',
-		dependencies:        '',
-		credentials:         `dns_joker_username = <Dynamic DNS Authentication Username>
-dns_joker_password = <Dynamic DNS Authentication Password>
-dns_joker_domain = <Dynamic DNS Domain>`,
-		full_plugin_name: 'dns-joker',
-	},
-	//####################################################//
-	linode: {
-		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',
-	},
-	//####################################################//
-	loopia: {
-		display_name:        'Loopia',
-		package_name:        'certbot-dns-loopia',
-		version_requirement: '~=1.0.0',
-		dependencies:        '',
-		credentials:         `dns_loopia_user = user@loopiaapi
-dns_loopia_password = abcdef0123456789abcdef01234567abcdef0123`,
-		full_plugin_name: 'dns-loopia',
-	},
-	//####################################################//
-	luadns: {
-		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',
-	},
-	//####################################################//
-	namecheap: {
-		display_name:        'Namecheap',
-		package_name:        'certbot-dns-namecheap',
-		version_requirement: '~=1.0.0',
-		dependencies:        '',
-		credentials:         `dns_namecheap_username  = 123456
-dns_namecheap_api_key      = 0123456789abcdef0123456789abcdef01234567`,
-		full_plugin_name: 'dns-namecheap',
-	},
-	//####################################################//
-	netcup: {
-		display_name:        'netcup',
-		package_name:        'certbot-dns-netcup',
-		version_requirement: '~=1.0.0',
-		dependencies:        '',
-		credentials:         `dns_netcup_customer_id  = 123456
-dns_netcup_api_key      = 0123456789abcdef0123456789abcdef01234567
-dns_netcup_api_password = abcdef0123456789abcdef01234567abcdef0123`,
-		full_plugin_name: 'dns-netcup',
-	},
-	//####################################################//
-	njalla: {
-		display_name:        'Njalla',
-		package_name:        'certbot-dns-njalla',
-		version_requirement: '~=1.0.0',
-		dependencies:        '',
-		credentials:         'dns_njalla_token = 0123456789abcdef0123456789abcdef01234567',
-		full_plugin_name:    'dns-njalla',
-	},
-	//####################################################//
-	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: {
-		display_name:    'Oracle Cloud Infrastructure DNS',
-		package_name:    'certbot-dns-oci',
-		package_version: '0.3.6',
-		dependencies:    'oci',
-		credentials:     `[DEFAULT]
-user = ocid1.user.oc1...
-fingerprint = xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx
-tenancy = ocid1.tenancy.oc1...
-region = us-ashburn-1
-key_file = ~/.oci/oci_api_key.pem`,
-		full_plugin_name: 'dns-oci',
-	},
-	//####################################################//
-	online: {
-		display_name:        'Online',
-		package_name:        'certbot-dns-online',
-		version_requirement: '~=0.0.8',
-		dependencies:        '',
-		credentials:         'dns_online_token=0123456789abcdef0123456789abcdef01234567',
-		full_plugin_name:    'dns-online',
-	},
-	//####################################################//
-	ovh: {
-		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`,
-		full_plugin_name: 'dns-ovh',
-	},
-	//####################################################//
-	plesk: {
-		display_name:        'Plesk',
-		package_name:        'certbot-dns-plesk',
-		version_requirement: '~=0.3.0',
-		dependencies:        '',
-		credentials:         `dns_plesk_username = your-username
-dns_plesk_password = secret
-dns_plesk_api_url = https://plesk-api-host:8443`,
-		full_plugin_name: 'dns-plesk',
-	},
-	//####################################################//
-	porkbun: {
-		display_name:        'Porkbun',
-		package_name:        'certbot-dns-porkbun',
-		version_requirement: '~=0.2',
-		dependencies:        '',
-		credentials:         `dns_porkbun_key=your-porkbun-api-key
-dns_porkbun_secret=your-porkbun-api-secret`,
-		full_plugin_name: 'dns-porkbun',
-	},
-	//####################################################//
-	powerdns: {
-		display_name:        'PowerDNS',
-		package_name:        'certbot-dns-powerdns',
-		version_requirement: '~=0.2.0',
-		dependencies:        '',
-		credentials:         `dns_powerdns_api_url = https://api.mypowerdns.example.org
-dns_powerdns_api_key = AbCbASsd!@34`,
-		full_plugin_name: 'dns-powerdns',
-	},
-	//####################################################//
-	regru: {
-		display_name:        'reg.ru',
-		package_name:        'certbot-regru',
-		version_requirement: '~=1.0.2',
-		dependencies:        '',
-		credentials:         `dns_username=username
-dns_password=password`,
-		full_plugin_name: 'dns',
-	},
-	//####################################################//
-	rfc2136: {
-		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
-# TSIG key name
-dns_rfc2136_name = keyname.
-# TSIG key secret
-dns_rfc2136_secret = 4q4wM/2I180UXoMyN4INVhJNi8V9BCV+jMw2mXgZw/CSuxUT8C7NKKFs AmKd7ak51vWKgSl12ib86oQRPkpDjg==
-# TSIG key algorithm
-dns_rfc2136_algorithm = HMAC-SHA512`,
-		full_plugin_name: 'dns-rfc2136',
-	},
-	//####################################################//
-	route53: {
-		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',
-	},
-	//####################################################//
-	strato: {
-		display_name:        'Strato',
-		package_name:        'certbot-dns-strato',
-		version_requirement: '~=0.1.1',
-		dependencies:        '',
-		credentials:         `dns_strato_username = user
-dns_strato_password = pass
-# uncomment if youre using two factor authentication:
-# dns_strato_totp_devicename = 2fa_device
-# dns_strato_totp_secret = 2fa_secret
-#
-# uncomment if domain name contains special characters
-# insert domain display name as seen on your account page here
-# dns_strato_domain_display_name = my-punicode-url.de
-#
-# if youre not using strato.de or another special endpoint you can customise it below
-# you will probably only need to adjust the host, but you can also change the complete endpoint url
-# dns_strato_custom_api_scheme = https
-# dns_strato_custom_api_host = www.strato.de
-# dns_strato_custom_api_port = 443
-# dns_strato_custom_api_path = "/apps/CustomerService"`,
-		full_plugin_name: 'dns-strato',
-	},
-	//####################################################//
-	transip: {
-		display_name:        'TransIP',
-		package_name:        'certbot-dns-transip',
-		version_requirement: '~=0.4.3',
-		dependencies:        '',
-		credentials:         `dns_transip_username = my_username
-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.2',
-		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',
-		version_requirement: '~=1.1.0',
-		dependencies:        '',
-		credentials:         'dns_vultr_key = YOUR_VULTR_API_KEY',
-		full_plugin_name:    'dns-vultr',
-	},
-	//####################################################//
-	websupportsk: {
-		display_name:        'Websupport.sk',
-		package_name:        'certbot-dns-websupportsk',
-		version_requirement: '~=0.1.6',
-		dependencies:        '',
-		credentials:         `dns_websupportsk_api_key = <api_key>
-dns_websupportsk_secret = <secret>
-dns_websupportsk_domain = example.com`,
-		full_plugin_name: 'dns-websupportsk',
-	},
-};

+ 426 - 0
global/certbot-dns-plugins.json

@@ -0,0 +1,426 @@
+{
+	"acmedns": {
+		"name": "ACME-DNS",
+		"package_name": "certbot-dns-acmedns",
+		"version": "~=0.1.0",
+		"dependencies": "",
+		"credentials": "dns_acmedns_api_url = http://acmedns-server/\ndns_acmedns_registration_file = /data/acme-registration.json",
+		"full_plugin_name": "dns-acmedns"
+	},
+	"aliyun": {
+		"name": "Aliyun",
+		"package_name": "certbot-dns-aliyun",
+		"version": "~=0.38.1",
+		"dependencies": "",
+		"credentials": "dns_aliyun_access_key = 12345678\ndns_aliyun_access_key_secret = 1234567890abcdef1234567890abcdef",
+		"full_plugin_name": "dns-aliyun"
+	},
+	"azure": {
+		"name": "Azure",
+		"package_name": "certbot-dns-azure",
+		"version": "~=1.2.0",
+		"dependencies": "",
+		"credentials": "# This plugin supported API authentication using either Service Principals or utilizing a Managed Identity assigned to the virtual machine.\n# Regardless which authentication method used, the identity will need the “DNS Zone Contributor” role assigned to it.\n# As multiple Azure DNS Zones in multiple resource groups can exist, the config file needs a mapping of zone to resource group ID. Multiple zones -> ID mappings can be listed by using the key dns_azure_zoneX where X is a unique number. At least 1 zone mapping is required.\n\n# Using a service principal (option 1)\ndns_azure_sp_client_id = 912ce44a-0156-4669-ae22-c16a17d34ca5\ndns_azure_sp_client_secret = E-xqXU83Y-jzTI6xe9fs2YC~mck3ZzUih9\ndns_azure_tenant_id = ed1090f3-ab18-4b12-816c-599af8a88cf7\n\n# Using used assigned MSI (option 2)\n# dns_azure_msi_client_id = 912ce44a-0156-4669-ae22-c16a17d34ca5\n\n# Using system assigned MSI (option 3)\n# dns_azure_msi_system_assigned = true\n\n# Zones (at least one always required)\ndns_azure_zone1 = example.com:/subscriptions/c135abce-d87d-48df-936c-15596c6968a5/resourceGroups/dns1\ndns_azure_zone2 = example.org:/subscriptions/99800903-fb14-4992-9aff-12eaf2744622/resourceGroups/dns2",
+		"full_plugin_name": "dns-azure"
+	},
+	"bunny": {
+		"name": "bunny.net",
+		"package_name": "certbot-dns-bunny",
+		"version": "~=0.0.9",
+		"dependencies": "",
+		"credentials": "# Bunny API token used by Certbot (see https://dash.bunny.net/account/settings)\ndns_bunny_api_key = xxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx",
+		"full_plugin_name": "dns-bunny"
+	},
+	"cloudflare": {
+		"name": "Cloudflare",
+		"package_name": "certbot-dns-cloudflare",
+		"version": "=={{certbot-version}}",
+		"dependencies": "cloudflare acme=={{certbot-version}}",
+		"credentials": "# Cloudflare API token\ndns_cloudflare_api_token = 0123456789abcdef0123456789abcdef01234567",
+		"full_plugin_name": "dns-cloudflare"
+	},
+	"cloudns": {
+		"name": "ClouDNS",
+		"package_name": "certbot-dns-cloudns",
+		"version": "~=0.4.0",
+		"dependencies": "",
+		"credentials": "# Target user ID (see https://www.cloudns.net/api-settings/)\n\tdns_cloudns_auth_id=1234\n\t# Alternatively, one of the following two options can be set:\n\t# dns_cloudns_sub_auth_id=1234\n\t# dns_cloudns_sub_auth_user=foobar\n\n\t# API password\n\tdns_cloudns_auth_password=password1",
+		"full_plugin_name": "dns-cloudns"
+	},
+	"cloudxns": {
+		"name": "CloudXNS",
+		"package_name": "certbot-dns-cloudxns",
+		"version": "~=1.32.0",
+		"dependencies": "",
+		"credentials": "dns_cloudxns_api_key = 1234567890abcdef1234567890abcdef\ndns_cloudxns_secret_key = 1122334455667788",
+		"full_plugin_name": "dns-cloudxns"
+	},
+	"constellix": {
+		"name": "Constellix",
+		"package_name": "certbot-dns-constellix",
+		"version": "~=0.2.1",
+		"dependencies": "",
+		"credentials": "dns_constellix_apikey = 5fb4e76f-ac91-43e5-f982458bc595\ndns_constellix_secretkey = 47d99fd0-32e7-4e07-85b46d08e70b\ndns_constellix_endpoint = https://api.dns.constellix.com/v1",
+		"full_plugin_name": "dns-constellix"
+	},
+	"corenetworks": {
+		"name": "Core Networks",
+		"package_name": "certbot-dns-corenetworks",
+		"version": "~=0.1.4",
+		"dependencies": "",
+		"credentials": "dns_corenetworks_username = asaHB12r\ndns_corenetworks_password = secure_password",
+		"full_plugin_name": "dns-corenetworks"
+	},
+	"cpanel": {
+		"name": "cPanel",
+		"package_name": "certbot-dns-cpanel",
+		"version": "~=0.2.2",
+		"dependencies": "",
+		"credentials": "cpanel_url = https://cpanel.example.com:2083\ncpanel_username = user\ncpanel_password = hunter2",
+		"full_plugin_name": "cpanel"
+	},
+	"desec": {
+		"name": "deSEC",
+		"package_name": "certbot-dns-desec",
+		"version": "~=1.2.1",
+		"dependencies": "",
+		"credentials": "dns_desec_token = YOUR_DESEC_API_TOKEN\ndns_desec_endpoint = https://desec.io/api/v1/",
+		"full_plugin_name": "dns-desec"
+	},
+	"duckdns": {
+		"name": "DuckDNS",
+		"package_name": "certbot-dns-duckdns",
+		"version": "~=0.9",
+		"dependencies": "",
+		"credentials": "dns_duckdns_token=your-duckdns-token",
+		"full_plugin_name": "dns-duckdns"
+	},
+	"digitalocean": {
+		"name": "DigitalOcean",
+		"package_name": "certbot-dns-digitalocean",
+		"version": "=={{certbot-version}}",
+		"dependencies": "acme=={{certbot-version}}",
+		"credentials": "dns_digitalocean_token = 0000111122223333444455556666777788889999aaaabbbbccccddddeeeeffff",
+		"full_plugin_name": "dns-digitalocean"
+	},
+	"directadmin": {
+		"name": "DirectAdmin",
+		"package_name": "certbot-dns-directadmin",
+		"version": "~=0.0.23",
+		"dependencies": "",
+		"credentials": "directadmin_url = https://my.directadminserver.com:2222\ndirectadmin_username = username\ndirectadmin_password = aSuperStrongPassword",
+		"full_plugin_name": "directadmin"
+	},
+	"dnsimple": {
+		"name": "DNSimple",
+		"package_name": "certbot-dns-dnsimple",
+		"version": "=={{certbot-version}}",
+		"dependencies": "acme=={{certbot-version}}",
+		"credentials": "dns_dnsimple_token = MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw",
+		"full_plugin_name": "dns-dnsimple"
+	},
+	"dnsmadeeasy": {
+		"name": "DNS Made Easy",
+		"package_name": "certbot-dns-dnsmadeeasy",
+		"version": "=={{certbot-version}}",
+		"dependencies": "acme=={{certbot-version}}",
+		"credentials": "dns_dnsmadeeasy_api_key = 1c1a3c91-4770-4ce7-96f4-54c0eb0e457a\ndns_dnsmadeeasy_secret_key = c9b5625f-9834-4ff8-baba-4ed5f32cae55",
+		"full_plugin_name": "dns-dnsmadeeasy"
+	},
+	"dnspod": {
+		"name": "DNSPod",
+		"package_name": "certbot-dns-dnspod",
+		"version": "~=0.1.0",
+		"dependencies": "",
+		"credentials": "dns_dnspod_email = \"[email protected]\"\ndns_dnspod_api_token = \"id,key\"",
+		"full_plugin_name": "dns-dnspod"
+	},
+	"domainoffensive": {
+		"name": "DomainOffensive (do.de)",
+		"package_name": "certbot-dns-do",
+		"version": "~=0.31.0",
+		"dependencies": "",
+		"credentials": "dns_do_api_token = YOUR_DO_DE_AUTH_TOKEN",
+		"full_plugin_name": "dns-do"
+	},
+	"domeneshop": {
+		"name": "Domeneshop",
+		"package_name": "certbot-dns-domeneshop",
+		"version": "~=0.2.8",
+		"dependencies": "",
+		"credentials": "dns_domeneshop_client_token=YOUR_DOMENESHOP_CLIENT_TOKEN\ndns_domeneshop_client_secret=YOUR_DOMENESHOP_CLIENT_SECRET",
+		"full_plugin_name": "dns-domeneshop"
+	},
+	"dynu": {
+		"name": "Dynu",
+		"package_name": "certbot-dns-dynu",
+		"version": "~=0.0.1",
+		"dependencies": "",
+		"credentials": "dns_dynu_auth_token = YOUR_DYNU_AUTH_TOKEN",
+		"full_plugin_name": "dns-dynu"
+	},
+	"eurodns": {
+		"name": "EuroDNS",
+		"package_name": "certbot-dns-eurodns",
+		"version": "~=0.0.4",
+		"dependencies": "",
+		"credentials": "dns_eurodns_applicationId = myuser\ndns_eurodns_apiKey = mysecretpassword\ndns_eurodns_endpoint = https://rest-api.eurodns.com/user-api-gateway/proxy",
+		"full_plugin_name": "dns-eurodns"
+	},
+	"gandi": {
+		"name": "Gandi Live DNS",
+		"package_name": "certbot_plugin_gandi",
+		"version": "~=1.5.0",
+		"dependencies": "",
+		"credentials": "# Gandi personal access token\ndns_gandi_token=PERSONAL_ACCESS_TOKEN",
+		"full_plugin_name": "dns-gandi"
+	},
+	"godaddy": {
+		"name": "GoDaddy",
+		"package_name": "certbot-dns-godaddy",
+		"version": "~=0.2.0",
+		"dependencies": "",
+		"credentials": "dns_godaddy_secret = 0123456789abcdef0123456789abcdef01234567\ndns_godaddy_key = abcdef0123456789abcdef01234567abcdef0123",
+		"full_plugin_name": "dns-godaddy"
+	},
+	"google": {
+		"name": "Google",
+		"package_name": "certbot-dns-google",
+		"version": "=={{certbot-version}}",
+		"dependencies": "",
+		"credentials": "{\n\"type\": \"service_account\",\n...\n}",
+		"full_plugin_name": "dns-google"
+	},
+	"googledomains": {
+		"name": "GoogleDomainsDNS",
+		"package_name": "certbot-dns-google-domains",
+		"version": "~=0.1.5",
+		"dependencies": "",
+		"credentials": "dns_google_domains_access_token = 0123456789abcdef0123456789abcdef01234567\ndns_google_domains_zone = \"example.com\"",
+		"full_plugin_name": "dns-google-domains"
+	},
+	"he": {
+		"name": "Hurricane Electric",
+		"package_name": "certbot-dns-he",
+		"version": "~=1.0.0",
+		"dependencies": "",
+		"credentials": "dns_he_user = Me\ndns_he_pass = my HE password",
+		"full_plugin_name": "dns-he"
+	},
+	"hetzner": {
+		"name": "Hetzner",
+		"package_name": "certbot-dns-hetzner",
+		"version": "~=1.0.4",
+		"dependencies": "",
+		"credentials": "dns_hetzner_api_token = 0123456789abcdef0123456789abcdef",
+		"full_plugin_name": "dns-hetzner"
+	},
+	"infomaniak": {
+		"name": "Infomaniak",
+		"package_name": "certbot-dns-infomaniak",
+		"version": "~=0.1.12",
+		"dependencies": "",
+		"credentials": "dns_infomaniak_token = XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+		"full_plugin_name": "dns-infomaniak"
+	},
+	"inwx": {
+		"name": "INWX",
+		"package_name": "certbot-dns-inwx",
+		"version": "~=2.1.2",
+		"dependencies": "",
+		"credentials": "dns_inwx_url = https://api.domrobot.com/xmlrpc/\ndns_inwx_username = your_username\ndns_inwx_password = your_password\ndns_inwx_shared_secret = your_shared_secret optional",
+		"full_plugin_name": "dns-inwx"
+	},
+	"ionos": {
+		"name": "IONOS",
+		"package_name": "certbot-dns-ionos",
+		"version": "==2022.11.24",
+		"dependencies": "",
+		"credentials": "dns_ionos_prefix = myapikeyprefix\ndns_ionos_secret = verysecureapikeysecret\ndns_ionos_endpoint = https://api.hosting.ionos.com",
+		"full_plugin_name": "dns-ionos"
+	},
+	"ispconfig": {
+		"name": "ISPConfig",
+		"package_name": "certbot-dns-ispconfig",
+		"version": "~=0.2.0",
+		"dependencies": "",
+		"credentials": "dns_ispconfig_username = myremoteuser\ndns_ispconfig_password = verysecureremoteuserpassword\ndns_ispconfig_endpoint = https://localhost:8080",
+		"full_plugin_name": "dns-ispconfig"
+	},
+	"isset": {
+		"name": "Isset",
+		"package_name": "certbot-dns-isset",
+		"version": "~=0.0.3",
+		"dependencies": "",
+		"credentials": "dns_isset_endpoint=\"https://customer.isset.net/api\"\ndns_isset_token=\"<token>\"",
+		"full_plugin_name": "dns-isset"
+	},
+	"joker": {
+		"name": "Joker",
+		"package_name": "certbot-dns-joker",
+		"version": "~=1.1.0",
+		"dependencies": "",
+		"credentials": "dns_joker_username = <Dynamic DNS Authentication Username>\ndns_joker_password = <Dynamic DNS Authentication Password>\ndns_joker_domain = <Dynamic DNS Domain>",
+		"full_plugin_name": "dns-joker"
+	},
+	"linode": {
+		"name": "Linode",
+		"package_name": "certbot-dns-linode",
+		"version": "=={{certbot-version}}",
+		"dependencies": "acme=={{certbot-version}}",
+		"credentials": "dns_linode_key = 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ64\ndns_linode_version = [<blank>|3|4]",
+		"full_plugin_name": "dns-linode"
+	},
+	"loopia": {
+		"name": "Loopia",
+		"package_name": "certbot-dns-loopia",
+		"version": "~=1.0.0",
+		"dependencies": "",
+		"credentials": "dns_loopia_user = user@loopiaapi\ndns_loopia_password = abcdef0123456789abcdef01234567abcdef0123",
+		"full_plugin_name": "dns-loopia"
+	},
+	"luadns": {
+		"name": "LuaDNS",
+		"package_name": "certbot-dns-luadns",
+		"version": "=={{certbot-version}}",
+		"dependencies": "acme=={{certbot-version}}",
+		"credentials": "dns_luadns_email = [email protected]\ndns_luadns_token = 0123456789abcdef0123456789abcdef",
+		"full_plugin_name": "dns-luadns"
+	},
+	"namecheap": {
+		"name": "Namecheap",
+		"package_name": "certbot-dns-namecheap",
+		"version": "~=1.0.0",
+		"dependencies": "",
+		"credentials": "dns_namecheap_username  = 123456\ndns_namecheap_api_key      = 0123456789abcdef0123456789abcdef01234567",
+		"full_plugin_name": "dns-namecheap"
+	},
+	"netcup": {
+		"name": "netcup",
+		"package_name": "certbot-dns-netcup",
+		"version": "~=1.0.0",
+		"dependencies": "",
+		"credentials": "dns_netcup_customer_id  = 123456\ndns_netcup_api_key      = 0123456789abcdef0123456789abcdef01234567\ndns_netcup_api_password = abcdef0123456789abcdef01234567abcdef0123",
+		"full_plugin_name": "dns-netcup"
+	},
+	"njalla": {
+		"name": "Njalla",
+		"package_name": "certbot-dns-njalla",
+		"version": "~=1.0.0",
+		"dependencies": "",
+		"credentials": "dns_njalla_token = 0123456789abcdef0123456789abcdef01234567",
+		"full_plugin_name": "dns-njalla"
+	},
+	"nsone": {
+		"name": "NS1",
+		"package_name": "certbot-dns-nsone",
+		"version": "=={{certbot-version}}",
+		"dependencies": "acme=={{certbot-version}}",
+		"credentials": "dns_nsone_api_key = MDAwMDAwMDAwMDAwMDAw",
+		"full_plugin_name": "dns-nsone"
+	},
+	"oci": {
+		"name": "Oracle Cloud Infrastructure DNS",
+		"package_name": "certbot-dns-oci",
+		"version": "~=0.3.6",
+		"dependencies": "oci",
+		"credentials": "[DEFAULT]\nuser = ocid1.user.oc1...\nfingerprint = xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx\ntenancy = ocid1.tenancy.oc1...\nregion = us-ashburn-1\nkey_file = ~/.oci/oci_api_key.pem",
+		"full_plugin_name": "dns-oci"
+	},
+	"ovh": {
+		"name": "OVH",
+		"package_name": "certbot-dns-ovh",
+		"version": "=={{certbot-version}}",
+		"dependencies": "acme=={{certbot-version}}",
+		"credentials": "dns_ovh_endpoint = ovh-eu\ndns_ovh_application_key = MDAwMDAwMDAwMDAw\ndns_ovh_application_secret = MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw\ndns_ovh_consumer_key = MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw",
+		"full_plugin_name": "dns-ovh"
+	},
+	"plesk": {
+		"name": "Plesk",
+		"package_name": "certbot-dns-plesk",
+		"version": "~=0.3.0",
+		"dependencies": "",
+		"credentials": "dns_plesk_username = your-username\ndns_plesk_password = secret\ndns_plesk_api_url = https://plesk-api-host:8443",
+		"full_plugin_name": "dns-plesk"
+	},
+	"porkbun": {
+		"name": "Porkbun",
+		"package_name": "certbot-dns-porkbun",
+		"version": "~=0.2",
+		"dependencies": "",
+		"credentials": "dns_porkbun_key=your-porkbun-api-key\ndns_porkbun_secret=your-porkbun-api-secret",
+		"full_plugin_name": "dns-porkbun"
+	},
+	"powerdns": {
+		"name": "PowerDNS",
+		"package_name": "certbot-dns-powerdns",
+		"version": "~=0.2.1",
+		"dependencies": "PyYAML==5.3.1",
+		"credentials": "dns_powerdns_api_url = https://api.mypowerdns.example.org\ndns_powerdns_api_key = AbCbASsd!@34",
+		"full_plugin_name": "dns-powerdns"
+	},
+	"regru": {
+		"name": "reg.ru",
+		"package_name": "certbot-regru",
+		"version": "~=1.0.2",
+		"dependencies": "",
+		"credentials": "dns_username=username\ndns_password=password",
+		"full_plugin_name": "dns"
+	},
+	"rfc2136": {
+		"name": "RFC 2136",
+		"package_name": "certbot-dns-rfc2136",
+		"version": "=={{certbot-version}}",
+		"dependencies": "acme=={{certbot-version}}",
+		"credentials": "# Target DNS server\ndns_rfc2136_server = 192.0.2.1\n# Target DNS port\ndns_rfc2136_port = 53\n# TSIG key name\ndns_rfc2136_name = keyname.\n# TSIG key secret\ndns_rfc2136_secret = 4q4wM/2I180UXoMyN4INVhJNi8V9BCV+jMw2mXgZw/CSuxUT8C7NKKFs AmKd7ak51vWKgSl12ib86oQRPkpDjg==\n# TSIG key algorithm\ndns_rfc2136_algorithm = HMAC-SHA512",
+		"full_plugin_name": "dns-rfc2136"
+	},
+	"route53": {
+		"name": "Route 53 (Amazon)",
+		"package_name": "certbot-dns-route53",
+		"version": "=={{certbot-version}}",
+		"dependencies": "acme=={{certbot-version}}",
+		"credentials": "[default]\naws_access_key_id=AKIAIOSFODNN7EXAMPLE\naws_secret_access_key=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
+		"full_plugin_name": "dns-route53"
+	},
+	"strato": {
+		"name": "Strato",
+		"package_name": "certbot-dns-strato",
+		"version": "~=0.1.1",
+		"dependencies": "",
+		"credentials": "dns_strato_username = user\ndns_strato_password = pass\n# uncomment if youre using two factor authentication:\n# dns_strato_totp_devicename = 2fa_device\n# dns_strato_totp_secret = 2fa_secret\n#\n# uncomment if domain name contains special characters\n# insert domain display name as seen on your account page here\n# dns_strato_domain_display_name = my-punicode-url.de\n#\n# if youre not using strato.de or another special endpoint you can customise it below\n# you will probably only need to adjust the host, but you can also change the complete endpoint url\n# dns_strato_custom_api_scheme = https\n# dns_strato_custom_api_host = www.strato.de\n# dns_strato_custom_api_port = 443\n# dns_strato_custom_api_path = \"/apps/CustomerService\"",
+		"full_plugin_name": "dns-strato"
+	},
+	"transip": {
+		"name": "TransIP",
+		"package_name": "certbot-dns-transip",
+		"version": "~=0.4.3",
+		"dependencies": "",
+		"credentials": "dns_transip_username = my_username\ndns_transip_key_file = /etc/letsencrypt/transip-rsa.key",
+		"full_plugin_name": "dns-transip"
+	},
+	"tencentcloud": {
+		"name": "Tencent Cloud",
+		"package_name": "certbot-dns-tencentcloud",
+		"version": "~=2.0.2",
+		"dependencies": "",
+		"credentials": "dns_tencentcloud_secret_id  = TENCENT_CLOUD_SECRET_ID\ndns_tencentcloud_secret_key = TENCENT_CLOUD_SECRET_KEY",
+		"full_plugin_name": "dns-tencentcloud"
+	},
+	"vultr": {
+		"name": "Vultr",
+		"package_name": "certbot-dns-vultr",
+		"version": "~=1.1.0",
+		"dependencies": "",
+		"credentials": "dns_vultr_key = YOUR_VULTR_API_KEY",
+		"full_plugin_name": "dns-vultr"
+	},
+	"websupportsk": {
+		"name": "Websupport.sk",
+		"package_name": "certbot-dns-websupportsk",
+		"version": "~=0.1.6",
+		"dependencies": "",
+		"credentials": "dns_websupportsk_api_key = <api_key>\ndns_websupportsk_secret = <secret>\ndns_websupportsk_domain = example.com",
+		"full_plugin_name": "dns-websupportsk"
+	}
+}

+ 3 - 0
global/test.js

@@ -0,0 +1,3 @@
+const c = require("./certbot-dns-plugins");
+
+console.log(JSON.stringify(c, null, 2));