227 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			227 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
		
			Executable File
		
	
	
	
	
| #!/usr/bin/env node
 | |
| 'use strict';
 | |
| 
 | |
| var fs = require('fs');
 | |
| var path = require('path');
 | |
| var mkdirp = require('fs');
 | |
| var cli = require('cli');
 | |
| var mkdirp = require('mkdirp');
 | |
| var homedir = require('os').homedir();
 | |
| var configDir = path.join(homedir, 'letsencrypt');
 | |
| var desktop = path.join(homedir, 'Desktop');
 | |
| var vhostDir = path.join(fs.existsSync(desktop) ? desktop : configDir, 'www');
 | |
| var welcomeHtml = fs.readFileSync(path.join(__dirname, '..', 'lib', 'public', 'welcome.html'), 'utf8');
 | |
| var express = require('express');
 | |
| 
 | |
| cli.parse({
 | |
|   'agree-tos': [ false, " Agree to the Let's Encrypt Subscriber Agreement", 'boolean', false ]
 | |
| , email: [ false, " Email used for registration and recovery contact. (default: null)", 'email' ]
 | |
| , domains: [ false, " Domain names to apply. To include the www domain with your main domain your can enter both with a comma. Ex --domains example.com,www.example.com (default: [])", 'string' ]
 | |
| , debug: [ false, " show traces and logs", 'boolean', false ]
 | |
| , server: [ false, " ACME Directory Resource URI.", 'string', 'https://acme-v01.api.letsencrypt.org/directory)' ]
 | |
| });
 | |
| 
 | |
| // ignore certonly and extraneous arguments
 | |
| cli.main(function(_, options) {
 | |
|   console.log('');
 | |
|   var args = {};
 | |
| 
 | |
|   Object.keys(options).forEach(function (key) {
 | |
|     var val = options[key];
 | |
| 
 | |
|     if ('string' === typeof val) {
 | |
|       val = val.replace(/^~/, homedir);
 | |
|     }
 | |
| 
 | |
|     key = key.replace(/\-([a-z0-9A-Z])/g, function (c) { return c[1].toUpperCase(); });
 | |
|     args[key] = val;
 | |
|   });
 | |
| 
 | |
|   if (args.domains) {
 | |
|     args.domains = args.domains.split(',');
 | |
|   }
 | |
| 
 | |
|   makeDirectories();
 | |
| 
 | |
|   function makeDirectories() {
 | |
|     mkdirp(configDir, function (err) {
 | |
|       if (err) {
 | |
|         console.error("Could not create config directory '" + configDir + "':", err.code);
 | |
|         console.error(err.stack);
 | |
|         return;
 | |
|       }
 | |
| 
 | |
|       mkdirp(vhostDir, function (err) {
 | |
|         if (err) {
 | |
|           console.error("Could not create vhost directory '" + vhostDir + "':", err.code);
 | |
|           console.error(err.stack);
 | |
|           return;
 | |
|         }
 | |
| 
 | |
|         startServers();
 | |
|       });
 | |
|     });
 | |
|   }
 | |
| 
 | |
|   function configure(le, args, cb) {
 | |
|     var vhost;
 | |
|     var pubDir;
 | |
|     var index;
 | |
| 
 | |
|     if (!(args.email && args.agreeTos && args.server && args.domains)) {
 | |
|       cb({ error : { message: "missing one or more of agreeTos,domains,email,server" } });
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|     vhost = args.domains[0];
 | |
|     pubDir = path.join(vhostDir, vhost);
 | |
|     index = path.join(pubDir, 'index.html');
 | |
| 
 | |
|     makeLandingPage();
 | |
| 
 | |
|     function makeLandingPage() {
 | |
|       mkdirp(pubDir, function (err) {
 | |
|         if (err) {
 | |
|           cb(err);
 | |
|           return;
 | |
|         }
 | |
| 
 | |
|         fs.exists(index, function (exists) {
 | |
|           if (exists) {
 | |
|             configureForHttps();
 | |
|             return;
 | |
|           }
 | |
| 
 | |
|           fs.writeFile(path.join(pubDir, 'index.html'), welcomeHtml.replace(/:hostname/g, vhost), 'utf8', function (err) {
 | |
|             if (err) {
 | |
|               cb(err);
 | |
|               return;
 | |
|             }
 | |
| 
 | |
|             configureForHttps();
 | |
|           });
 | |
|         });
 | |
|       });
 | |
|     }
 | |
| 
 | |
|     function configureForHttps() {
 | |
|       if (args.debug) {
 | |
|         console.log('[LEX] configureForHttps');
 | |
|         console.log(args);
 | |
|       }
 | |
|       le.setConfig(args, cb);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   function createConfigurator(le) {
 | |
|     var app = express();
 | |
| 
 | |
|     app.use('/', express.static(path.join(__dirname, '..', 'lib', 'configurator')));
 | |
| 
 | |
|     app.use(require('body-parser').json());
 | |
| 
 | |
|     app.get('/api/com.daplie.lex/sites', function (req, res, next) {
 | |
|       le.getConfigs({ configDir: configDir }, function (err, configs) {
 | |
|         if (err) {
 | |
|           next(err);
 | |
|           return;
 | |
|         }
 | |
|         res.send(configs);
 | |
|       });
 | |
|     });
 | |
| 
 | |
|     app.post('/api/com.daplie.lex/sites', function (req, res, next) {
 | |
|       var data = req.body;
 | |
| 
 | |
|       configure(le, data, function (err, configs) {
 | |
|         if (err) {
 | |
|           console.error(err.stack);
 | |
|           next(err);
 | |
|           return;
 | |
|         }
 | |
| 
 | |
|         res.send(configs);
 | |
|       });
 | |
|     });
 | |
| 
 | |
|     return app;
 | |
|   }
 | |
| 
 | |
|   function startServers() {
 | |
|     // Note: using staging server url, remove .testing() for production
 | |
|     var LE = require('letsencrypt');
 | |
|     var challengeStore = require('../lib/challenge-handlers');
 | |
|     var le = LE.create({
 | |
|       configDir: configDir
 | |
|     , manual: true
 | |
| 
 | |
|     , privkeyPath: LE.privkeyPath
 | |
|     , fullchainPath: LE.fullchainPath
 | |
|     , certPath: LE.certPath
 | |
|     , chainPath: LE.chainPath
 | |
|     , renewalPath: LE.renewalPath
 | |
|     , accountsDir: LE.accountsDir
 | |
|     }, {
 | |
|       setChallenge: challengeStore.set
 | |
|     , removeChallenge: challengeStore.remove
 | |
|     });
 | |
|     var lex = require('../');
 | |
|     var app = express();
 | |
|     var vhosts = {};
 | |
| 
 | |
|     vhosts['localhost.daplie.com'] = createConfigurator(le, vhosts);
 | |
| 
 | |
|     app.use('/', function (req, res, next) {
 | |
|       var hostname = (req.hostname||req.headers.host||'').replace(/^www\./, '');
 | |
|       var pubDir = path.join(vhostDir, hostname);
 | |
| 
 | |
|       if (vhosts[hostname]) {
 | |
|         vhosts[hostname](req, res, next);
 | |
|         return;
 | |
|       }
 | |
| 
 | |
|       fs.exists(pubDir, function (exists) {
 | |
|         if (exists) {
 | |
|           vhosts[hostname] = express().use('/', express.static(pubDir));
 | |
|           vhosts[hostname](req, res, next);
 | |
|         } else {
 | |
|           vhosts['localhost.daplie.com'](req, res, next);
 | |
|         }
 | |
|       });
 | |
|     });
 | |
|     app.use('/', express.static(path.join(__dirname, '..', 'lib', 'public')));
 | |
| 
 | |
|     lex.create({
 | |
|       onRequest: app
 | |
|     , configDir: configDir
 | |
|     , letsencrypt: le
 | |
|     , approveRegistration: function (domain, cb) {
 | |
|         le.getConfig({ domains: [domain] }, function (err, config) {
 | |
|           if (!(config && config.checkpoints >= 0)) {
 | |
|             cb(null, null);
 | |
|             return;
 | |
|           }
 | |
| 
 | |
|           cb(null, {
 | |
|             email: config.email
 | |
|                 // can't remember which it is, but the pyconf is different that the regular variable
 | |
|           , agreeTos: config.tos || config.agree || config.agreeTos
 | |
|           , server: config.server || LE.productionServerUrl
 | |
|           , domains: config.domains || [domain]
 | |
|           });
 | |
|         });
 | |
|       }
 | |
|     }).listen([80], [443, 5001]);
 | |
|   }
 | |
| 
 | |
|   /*
 | |
|       // should get back account, path to certs, pems, etc?
 | |
|       console.log('\nCertificates installed at:');
 | |
|       console.log(Object.keys(results).filter(function (key) {
 | |
|         return /Path/.test(key);
 | |
|       }).map(function (key) {
 | |
|         return results[key];
 | |
|       }).join('\n'));
 | |
|   */
 | |
| });
 |