228 lines
6.3 KiB
JavaScript
Executable File
228 lines
6.3 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("[LEX/bin] configure");
|
|
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'));
|
|
*/
|
|
});
|