Skip to content

Commit 96f401c

Browse files
authored
Merge pull request #664 from chaptergy/fixes-expiring-hosts-renewal
Adds certbot plugin installation check on startup
2 parents ffd2430 + 08ab621 commit 96f401c

File tree

4 files changed

+67
-34
lines changed

4 files changed

+67
-34
lines changed

backend/internal/certificate.js

Lines changed: 22 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -788,7 +788,7 @@ const internalCertificate = {
788788

789789
logger.info(`Requesting Let'sEncrypt certificates via ${dns_plugin.display_name} for Cert #${certificate.id}: ${certificate.domain_names.join(', ')}`);
790790

791-
const credentials_loc = '/etc/letsencrypt/credentials-' + certificate.id;
791+
const credentials_loc = '/etc/letsencrypt/credentials/credentials-' + certificate.id;
792792
const credentials_cmd = 'echo \'' + certificate.meta.dns_provider_credentials.replace('\'', '\\\'') + '\' > \'' + credentials_loc + '\' && chmod 600 \'' + credentials_loc + '\'';
793793
const prepare_cmd = 'pip3 install ' + dns_plugin.package_name + '==' + dns_plugin.package_version;
794794

@@ -818,11 +818,9 @@ const internalCertificate = {
818818
if (certificate.meta.dns_provider === 'route53') {
819819
main_cmd = 'AWS_CONFIG_FILE=\'' + credentials_loc + '\' ' + main_cmd;
820820
}
821-
822-
const teardown_cmd = `rm '${credentials_loc}'`;
823821

824822
if (debug_mode) {
825-
logger.info('Command:', `${credentials_cmd} && ${prepare_cmd} && ${main_cmd} && ${teardown_cmd}`);
823+
logger.info('Command:', `${credentials_cmd} && ${prepare_cmd} && ${main_cmd}`);
826824
}
827825

828826
return utils.exec(credentials_cmd)
@@ -831,11 +829,15 @@ const internalCertificate = {
831829
.then(() => {
832830
return utils.exec(main_cmd)
833831
.then(async (result) => {
834-
await utils.exec(teardown_cmd);
835832
logger.info(result);
836833
return result;
837834
});
838835
});
836+
}).catch(async (err) => {
837+
// Don't fail if file does not exist
838+
const delete_credentials_cmd = `rm -f '${credentials_loc}' || true`;
839+
await utils.exec(delete_credentials_cmd);
840+
throw err;
839841
});
840842
},
841843

@@ -922,10 +924,6 @@ const internalCertificate = {
922924

923925
logger.info(`Renewing Let'sEncrypt certificates via ${dns_plugin.display_name} for Cert #${certificate.id}: ${certificate.domain_names.join(', ')}`);
924926

925-
const credentials_loc = '/etc/letsencrypt/credentials-' + certificate.id;
926-
const credentials_cmd = 'echo \'' + certificate.meta.dns_provider_credentials.replace('\'', '\\\'') + '\' > \'' + credentials_loc + '\' && chmod 600 \'' + credentials_loc + '\'';
927-
const prepare_cmd = 'pip3 install ' + dns_plugin.package_name + '==' + dns_plugin.package_version;
928-
929927
let main_cmd =
930928
certbot_command + ' renew --non-interactive ' +
931929
'--cert-name "npm-' + certificate.id + '" ' +
@@ -934,26 +932,18 @@ const internalCertificate = {
934932

935933
// Prepend the path to the credentials file as an environment variable
936934
if (certificate.meta.dns_provider === 'route53') {
937-
main_cmd = 'AWS_CONFIG_FILE=\'' + credentials_loc + '\' ' + main_cmd;
935+
const credentials_loc = '/etc/letsencrypt/credentials/credentials-' + certificate.id;
936+
main_cmd = 'AWS_CONFIG_FILE=\'' + credentials_loc + '\' ' + main_cmd;
938937
}
939938

940-
const teardown_cmd = `rm '${credentials_loc}'`;
941-
942939
if (debug_mode) {
943-
logger.info('Command:', `${credentials_cmd} && ${prepare_cmd} && ${main_cmd} && ${teardown_cmd}`);
940+
logger.info('Command:', main_cmd);
944941
}
945942

946-
return utils.exec(credentials_cmd)
947-
.then(() => {
948-
return utils.exec(prepare_cmd)
949-
.then(() => {
950-
return utils.exec(main_cmd)
951-
.then(async (result) => {
952-
await utils.exec(teardown_cmd);
953-
logger.info(result);
954-
return result;
955-
});
956-
});
943+
return utils.exec(main_cmd)
944+
.then(async (result) => {
945+
logger.info(result);
946+
return result;
957947
});
958948
},
959949

@@ -965,20 +955,21 @@ const internalCertificate = {
965955
revokeLetsEncryptSsl: (certificate, throw_errors) => {
966956
logger.info('Revoking Let\'sEncrypt certificates for Cert #' + certificate.id + ': ' + certificate.domain_names.join(', '));
967957

968-
let cmd = certbot_command + ' revoke --non-interactive ' +
958+
const main_cmd = certbot_command + ' revoke --non-interactive ' +
969959
'--cert-path "/etc/letsencrypt/live/npm-' + certificate.id + '/fullchain.pem" ' +
970960
'--delete-after-revoke ' +
971961
(le_staging ? '--staging' : '');
972962

963+
// Don't fail command if file does not exist
964+
const delete_credentials_cmd = `rm -f '/etc/letsencrypt/credentials/credentials-${certificate.id}' || true`;
965+
973966
if (debug_mode) {
974-
logger.info('Command:', cmd);
967+
logger.info('Command:', main_cmd + '; ' + delete_credentials_cmd);
975968
}
976969

977-
return utils.exec(cmd)
978-
.then((result) => {
979-
if (debug_mode) {
980-
logger.info('Command:', cmd);
981-
}
970+
return utils.exec(main_cmd)
971+
.then(async (result) => {
972+
await utils.exec(delete_credentials_cmd);
982973
logger.info(result);
983974
return result;
984975
})

backend/setup.js

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,13 @@ const fs = require('fs');
22
const NodeRSA = require('node-rsa');
33
const config = require('config');
44
const logger = require('./logger').setup;
5+
const certificateModel = require('./models/certificate');
56
const userModel = require('./models/user');
67
const userPermissionModel = require('./models/user_permission');
8+
const utils = require('./lib/utils');
79
const authModel = require('./models/auth');
810
const settingModel = require('./models/setting');
11+
const dns_plugins = require('./global/certbot-dns-plugins');
912
const debug_mode = process.env.NODE_ENV !== 'production' || !!process.env.DEBUG;
1013

1114
/**
@@ -155,8 +158,47 @@ const setupDefaultSettings = () => {
155158
});
156159
};
157160

161+
/**
162+
* Installs all Certbot plugins which are required for an installed certificate
163+
*
164+
* @returns {Promise}
165+
*/
166+
const setupCertbotPlugins = () => {
167+
return certificateModel
168+
.query()
169+
.where('is_deleted', 0)
170+
.andWhere('provider', 'letsencrypt')
171+
.then((certificates) => {
172+
if (certificates && certificates.length) {
173+
let plugins = [];
174+
let promises = [];
175+
176+
certificates.map(function (certificate) {
177+
if (certificate.meta && certificate.meta.dns_challenge === true) {
178+
const dns_plugin = dns_plugins[certificate.meta.dns_provider];
179+
const package_to_install = `${dns_plugin.package_name}==${dns_plugin.package_version}`;
180+
181+
if (plugins.indexOf(package_to_install) === -1) plugins.push(package_to_install);
182+
183+
// Make sure credentials file exists
184+
const credentials_loc = '/etc/letsencrypt/credentials/credentials-' + certificate.id;
185+
const credentials_cmd = '[ -f \'' + credentials_loc + '\' ] || { mkdir /etc/letsencrypt/credentials; echo \'' + certificate.meta.dns_provider_credentials.replace('\'', '\\\'') + '\' > \'' + credentials_loc + '\' && chmod 600 \'' + credentials_loc + '\'; }';
186+
promises.push(utils.exec(credentials_cmd));
187+
}
188+
});
189+
190+
const install_cmd = 'pip3 install ' + plugins.join(' ');
191+
promises.push(utils.exec(install_cmd));
192+
return Promise.all(promises).then(() => {
193+
logger.info('Added Certbot plugins ' + plugins.join(', '));
194+
});
195+
}
196+
});
197+
};
198+
158199
module.exports = function () {
159200
return setupJwt()
160201
.then(setupDefaultUser)
161-
.then(setupDefaultSettings);
202+
.then(setupDefaultSettings)
203+
.then(setupCertbotPlugins);
162204
};

frontend/js/i18n/messages.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@
109109
"please-choose": "Please Choose...",
110110
"credentials-file-content": "Credentials File Content",
111111
"credentials-file-content-info": "This plugin requires a configuration file containing an API token or other credentials to your provider",
112-
"stored-as-plaintext-info": "This data will be stored as plaintext in the database!",
112+
"stored-as-plaintext-info": "This data will be stored as plaintext in the database and in a file!",
113113
"propagation-seconds": "Propagation Seconds",
114114
"propagation-seconds-info": "Leave empty to use the plugins default value. Number of seconds to wait for DNS propagation.",
115115
"processing-info": "Processing... This might take a few minutes."

global/certbot-dns-plugins.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ dns_netcup_api_password = abcdef0123456789abcdef01234567abcdef0123`,
181181
njalla: {
182182
display_name: 'Njalla',
183183
package_name: 'certbot-dns-njalla',
184-
package_version: '0.0.4',
184+
package_version: '1.0.0',
185185
credentials: 'certbot_dns_njalla:dns_njalla_token = 0123456789abcdef0123456789abcdef01234567',
186186
full_plugin_name: 'certbot-dns-njalla:dns-njalla',
187187
},

0 commit comments

Comments
 (0)