diff --git a/src/certificates.js b/src/certificates.js index 8bf9165d1..075b684af 100644 --- a/src/certificates.js +++ b/src/certificates.js @@ -5,9 +5,14 @@ var acme = require('./cert/acme.js'), assert = require('assert'), config = require('./config.js'), + constants = require('./constants.js'), debug = require('debug')('src/certificates'), + ejs = require('ejs'), + fs = require('fs'), + path = require('path'), paths = require('./paths.js'), safe = require('safetydance'), + shell = require('./shell.js'), sysinfo = require('./sysinfo.js'), util = require('util'), x509 = require('x509'); @@ -16,7 +21,10 @@ exports = module.exports = { initialize: initialize, uninitialize: uninitialize, autoRenew: autoRenew, - validateCertificate: validateCertificate + setAppCertificate: setAppCertificate, + setAdminCertificate: setAdminCertificate, + CertificatesError: CertificatesError, + validateCertificate: validateCertificate, }; function CertificatesError(reason, errorOrMessage) { @@ -41,6 +49,9 @@ util.inherits(CertificatesError, Error); CertificatesError.INTERNAL_ERROR = 'Internal Error'; CertificatesError.INVALID_CERT = 'Invalid certificate'; +var NGINX_APPCONFIG_EJS = fs.readFileSync(__dirname + '/../setup/start/nginx/appconfig.ejs', { encoding: 'utf8' }), + RELOAD_NGINX_CMD = path.join(__dirname, 'scripts/reloadnginx.sh'); + function initialize(callback) { if (!config.isCustomDomain()) return callback(); @@ -100,3 +111,64 @@ function validateCertificate(cert, key, fqdn) { return null; } + +function setAppCertificate(cert, key, callback) { + assert.strictEqual(typeof cert, 'string'); + assert.strictEqual(typeof key, 'string'); + assert.strictEqual(typeof callback, 'function'); + + var error = validateCertificate(cert, key, '*.' + config.fqdn()); + if (error) return callback(new CertificatesError(CertificatesError.INVALID_CERT, error.message)); + + // backup the cert + if (!safe.fs.writeFileSync(path.join(paths.APP_CERTS_DIR, 'host.cert'), cert)) return callback(new CertificatesError(CertificatesError.INTERNAL_ERROR, safe.error.message)); + if (!safe.fs.writeFileSync(path.join(paths.APP_CERTS_DIR, 'host.key'), key)) return callback(new CertificatesError(CertificatesError.INTERNAL_ERROR, safe.error.message)); + + // copy over fallback cert + if (!safe.fs.writeFileSync(path.join(paths.NGINX_CERT_DIR, 'host.cert'), cert)) return callback(new CertificatesError(CertificatesError.INTERNAL_ERROR, safe.error.message)); + if (!safe.fs.writeFileSync(path.join(paths.NGINX_CERT_DIR, 'host.key'), key)) return callback(new CertificatesError(CertificatesError.INTERNAL_ERROR, safe.error.message)); + + shell.sudo('setCertificate', [ RELOAD_NGINX_CMD ], function (error) { + if (error) return callback(new CertificatesError(CertificatesError.INTERNAL_ERROR, error)); + + return callback(null); + }); +} + +function setAdminCertificate(cert, key, callback) { + assert.strictEqual(typeof cert, 'string'); + assert.strictEqual(typeof key, 'string'); + assert.strictEqual(typeof callback, 'function'); + + var sourceDir = path.resolve(__dirname, '..'); + var endpoint = 'admin'; + var vhost = config.appFqdn(constants.ADMIN_LOCATION); + var certFilePath = path.join(paths.APP_CERTS_DIR, vhost + '.cert'); + var keyFilePath = path.join(paths.APP_CERTS_DIR, vhost + '.key'); + + var error = validateCertificate(cert, key, vhost); + if (error) return callback(new CertificatesError(CertificatesError.INVALID_CERT, error.message)); + + // backup the cert + if (!safe.fs.writeFileSync(certFilePath, cert)) return callback(new CertificatesError(CertificatesError.INTERNAL_ERROR, safe.error.message)); + if (!safe.fs.writeFileSync(keyFilePath, key)) return callback(new CertificatesError(CertificatesError.INTERNAL_ERROR, safe.error.message)); + + var data = { + sourceDir: sourceDir, + adminOrigin: config.adminOrigin(), + vhost: vhost, + endpoint: endpoint, + certFilePath: certFilePath, + keyFilePath: keyFilePath + }; + var nginxConf = ejs.render(NGINX_APPCONFIG_EJS, data); + var nginxConfigFilename = path.join(paths.NGINX_APPCONFIG_DIR, 'admin.conf'); + + if (!safe.fs.writeFileSync(nginxConfigFilename, nginxConf)) return callback(safe.error); + + shell.sudo('setAdminCertificate', [ RELOAD_NGINX_CMD ], function (error) { + if (error) return callback(new CertificatesError(CertificatesError.INTERNAL_ERROR, error)); + + return callback(null); + }); +} diff --git a/src/routes/settings.js b/src/routes/settings.js index 0edbafded..510bea59a 100644 --- a/src/routes/settings.js +++ b/src/routes/settings.js @@ -23,6 +23,8 @@ exports = module.exports = { }; var assert = require('assert'), + certificates = require('../certificates.js'), + CertificatesError = require('../certificates.js').CertificatesError, HttpError = require('connect-lastmile').HttpError, HttpSuccess = require('connect-lastmile').HttpSuccess, safe = require('safetydance'), @@ -142,8 +144,8 @@ function setCertificate(req, res, next) { if (!req.body.cert || typeof req.body.cert !== 'string') return next(new HttpError(400, 'cert must be a string')); if (!req.body.key || typeof req.body.key !== 'string') return next(new HttpError(400, 'key must be a string')); - settings.setCertificate(req.body.cert, req.body.key, function (error) { - if (error && error.reason === SettingsError.INVALID_CERT) return next(new HttpError(400, error.message)); + certificates.setAppCertificate(req.body.cert, req.body.key, function (error) { + if (error && error.reason === CertificatesError.INVALID_CERT) return next(new HttpError(400, error.message)); if (error) return next(new HttpError(500, error)); next(new HttpSuccess(202, {})); @@ -157,8 +159,8 @@ function setAdminCertificate(req, res, next) { if (!req.body.cert || typeof req.body.cert !== 'string') return next(new HttpError(400, 'cert must be a string')); if (!req.body.key || typeof req.body.key !== 'string') return next(new HttpError(400, 'key must be a string')); - settings.setAdminCertificate(req.body.cert, req.body.key, function (error) { - if (error && error.reason === SettingsError.INVALID_CERT) return next(new HttpError(400, error.message)); + certificates.setAdminCertificate(req.body.cert, req.body.key, function (error) { + if (error && error.reason === CertificatesError.INVALID_CERT) return next(new HttpError(400, error.message)); if (error) return next(new HttpError(500, error)); next(new HttpSuccess(202, {})); diff --git a/src/settings.js b/src/settings.js index c00534d2e..ffbb0053c 100644 --- a/src/settings.js +++ b/src/settings.js @@ -29,9 +29,6 @@ exports = module.exports = { getDefaultSync: getDefaultSync, getAll: getAll, - setCertificate: setCertificate, - setAdminCertificate: setAdminCertificate, - AUTOUPDATE_PATTERN_KEY: 'autoupdate_pattern', TIME_ZONE_KEY: 'time_zone', CLOUDRON_NAME_KEY: 'cloudron_name', @@ -43,18 +40,12 @@ exports = module.exports = { }; var assert = require('assert'), - certificates = require('./certificates.js'), config = require('./config.js'), - constants = require('./constants.js'), CronJob = require('cron').CronJob, DatabaseError = require('./databaseerror.js'), - ejs = require('ejs'), - fs = require('fs'), - path = require('path'), paths = require('./paths.js'), safe = require('safetydance'), settingsdb = require('./settingsdb.js'), - shell = require('./shell.js'), util = require('util'), _ = require('underscore'); @@ -70,9 +61,6 @@ var gDefaults = (function () { return result; })(); -var NGINX_APPCONFIG_EJS = fs.readFileSync(__dirname + '/../setup/start/nginx/appconfig.ejs', { encoding: 'utf8' }), - RELOAD_NGINX_CMD = path.join(__dirname, 'scripts/reloadnginx.sh'); - if (config.TEST) { // avoid noisy warnings during npm test exports.events.setMaxListeners(100); @@ -100,7 +88,6 @@ util.inherits(SettingsError, Error); SettingsError.INTERNAL_ERROR = 'Internal Error'; SettingsError.NOT_FOUND = 'Not Found'; SettingsError.BAD_FIELD = 'Bad Field'; -SettingsError.INVALID_CERT = 'Invalid certificate'; function setAutoupdatePattern(pattern, callback) { assert.strictEqual(typeof pattern, 'string'); @@ -321,64 +308,3 @@ function getAll(callback) { callback(null, result); }); } - -function setCertificate(cert, key, callback) { - assert.strictEqual(typeof cert, 'string'); - assert.strictEqual(typeof key, 'string'); - assert.strictEqual(typeof callback, 'function'); - - var error = certificates.validateCertificate(cert, key, '*.' + config.fqdn()); - if (error) return callback(new SettingsError(SettingsError.INVALID_CERT, error.message)); - - // backup the cert - if (!safe.fs.writeFileSync(path.join(paths.APP_CERTS_DIR, 'host.cert'), cert)) return callback(new SettingsError(SettingsError.INTERNAL_ERROR, safe.error.message)); - if (!safe.fs.writeFileSync(path.join(paths.APP_CERTS_DIR, 'host.key'), key)) return callback(new SettingsError(SettingsError.INTERNAL_ERROR, safe.error.message)); - - // copy over fallback cert - if (!safe.fs.writeFileSync(path.join(paths.NGINX_CERT_DIR, 'host.cert'), cert)) return callback(new SettingsError(SettingsError.INTERNAL_ERROR, safe.error.message)); - if (!safe.fs.writeFileSync(path.join(paths.NGINX_CERT_DIR, 'host.key'), key)) return callback(new SettingsError(SettingsError.INTERNAL_ERROR, safe.error.message)); - - shell.sudo('setCertificate', [ RELOAD_NGINX_CMD ], function (error) { - if (error) return callback(new SettingsError(SettingsError.INTERNAL_ERROR, error)); - - return callback(null); - }); -} - -function setAdminCertificate(cert, key, callback) { - assert.strictEqual(typeof cert, 'string'); - assert.strictEqual(typeof key, 'string'); - assert.strictEqual(typeof callback, 'function'); - - var sourceDir = path.resolve(__dirname, '..'); - var endpoint = 'admin'; - var vhost = config.appFqdn(constants.ADMIN_LOCATION); - var certFilePath = path.join(paths.APP_CERTS_DIR, vhost + '.cert'); - var keyFilePath = path.join(paths.APP_CERTS_DIR, vhost + '.key'); - - var error = certificates.validateCertificate(cert, key, vhost); - if (error) return callback(new SettingsError(SettingsError.INVALID_CERT, error.message)); - - // backup the cert - if (!safe.fs.writeFileSync(certFilePath, cert)) return callback(new SettingsError(SettingsError.INTERNAL_ERROR, safe.error.message)); - if (!safe.fs.writeFileSync(keyFilePath, key)) return callback(new SettingsError(SettingsError.INTERNAL_ERROR, safe.error.message)); - - var data = { - sourceDir: sourceDir, - adminOrigin: config.adminOrigin(), - vhost: vhost, - endpoint: endpoint, - certFilePath: certFilePath, - keyFilePath: keyFilePath - }; - var nginxConf = ejs.render(NGINX_APPCONFIG_EJS, data); - var nginxConfigFilename = path.join(paths.NGINX_APPCONFIG_DIR, 'admin.conf'); - - if (!safe.fs.writeFileSync(nginxConfigFilename, nginxConf)) return callback(safe.error); - - shell.sudo('setAdminCertificate', [ RELOAD_NGINX_CMD ], function (error) { - if (error) return callback(new SettingsError(SettingsError.INTERNAL_ERROR, error)); - - return callback(null); - }); -}