var LE = require('letsencrypt'); var pem = require('pem'); var RSVP = require('rsvp'); var fs = require('fs'); var path = require('path'); var mkdirp = require('mkdirp'); var domains, herokuAppName, duplicate; if (process.env.YAPP_ENV === 'qa') { domains = ['heroku.yappqa.us', 'my.yappqa.us', 'api.yappqa.us', 'support.yappqa.us' ]; herokuAppName = 'qa-yapp-cedar'; duplicate = true; // create new cert even if they are less than 1 week old } else if (process.env.YAPP_ENV === 'prod') { domains = ['heroku.yapp.us', 'my.yapp.us', 'api.yapp.us', 'support.yapp.us']; herokuAppName = 'yapp-cedar'; duplicate = false; } else { throw new Error('Must provide valid YAPP_ENV (qa or prod)'); } var redisUrlExtraction = new RSVP.Promise(function(resolve, reject){ var exec = require('child_process').exec; exec('heroku config:get REDISTOGO_URL --app ' + herokuAppName, function (error, stdout, stderr) { var redisUrl = stdout.replace(/\n/, '').replace(/\/\/redistogo:/, '//:'); if (error) { reject(error); } else { resolve(redisUrl); } }); }); var createPrivateKey = RSVP.denodeify(pem.createPrivateKey); var privateKeyGeneration = createPrivateKey(2048).then(function(privateKey) { var pemPath = require('homedir')() + '/letsencrypt/etc/live/' + domains[0] + '/privkey.pem'; mkdirp.sync(path.dirname(pemPath)); fs.writeFileSync(pemPath, privateKey.key); }).catch(function(reason){ console.log(reason); throw reason; }); privateKeyGeneration.then(function(){ var config = { server: LE.productionServerUrl, manual: true, configDir: require('homedir')() + '/letsencrypt/etc', privkeyPath: ':config/live/:hostname/privkey.pem', fullchainPath: ':config/live/:hostname/fullchain.pem', certPath: ':config/live/:hostname/cert.pem', chainPath: ':config/live/:hostname/chain.pem', debug: true }; var handlers = { setChallenge: function (opts, hostname, key, val, cb) { // called during the ACME server handshake, before validation redisUrlExtraction.then(function(redisUrl){ var redis = require("redis"); var redisClient = redis.createClient(redisUrl); redisClient.set("letsencrypt:" + key, val, function(err){ // console.log("set redis key letsencrypt:" + key + " = " + val); if (err) { console.log(err); throw err; } cb(); }); }).catch(function(reason){ console.log(reason); throw reason; }); }, removeChallenge: function (opts, hostname, key, cb) {} // called after validation on both success and failure }; var le = LE.create(config, handlers); le.register({ // either renews or registers domains: domains, email: 'tech@yapp.us', agreeTos: true, duplicate: true }, function (err, results) { if (err) { console.error('[Error]: node-letsencrypt'); console.error(err.stack || err); return; } if (!results || ('object' !== typeof results)) { console.error("Error: An unknown error occurred. My best guess is that we got an error that we're not used to from the ACME server and accidentally interpretted it as a success... or forgot to expose the error."); console.error(results); err = new Error("Here's a stack trace, in case it helps:"); console.error(err.stack); return; } // if (handlers.closeServers) { // handlers.closeServers(); // } console.log('\nCertificate files downloaded! Please run:'); console.log("heroku certs:update " + results.fullchainPath + ' ' + results.privkeyPath + ' --app ' + herokuAppName); process.exit(0); }); });