a special treat
This commit is contained in:
parent
7a208b0308
commit
8ccd89ddfd
|
@ -0,0 +1,222 @@
|
||||||
|
#!/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() {
|
||||||
|
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
|
||||||
|
}, {
|
||||||
|
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.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], function () {
|
||||||
|
console.log("ENCRYPT __ALL__ THE DOMAINS!");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
// 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'));
|
||||||
|
*/
|
||||||
|
});
|
|
@ -0,0 +1,41 @@
|
||||||
|
$(function () {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var tpl = $('.js-hostnames').html();
|
||||||
|
$('.js-hostnames').html('');
|
||||||
|
|
||||||
|
$('body').on('submit', 'form.js-add-site', function (ev) {
|
||||||
|
ev.preventDefault();
|
||||||
|
// I don't think this actually has any meaning when listening on body
|
||||||
|
ev.stopPropagation();
|
||||||
|
|
||||||
|
var data = {
|
||||||
|
email: $('.js-email').val()
|
||||||
|
, agreeTos: !!$('.js-agree-tos').prop('checked')
|
||||||
|
, server: $('.js-server').val()
|
||||||
|
, domains: $('.js-domains').val().split(/\s*,\s*/)
|
||||||
|
};
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
method: 'POST'
|
||||||
|
, url: '/api/com.daplie.lex/sites'
|
||||||
|
, data: JSON.stringify(data)
|
||||||
|
, headers: { 'Content-Type': 'application/json; charset=utf-8' }
|
||||||
|
}).then(function (data) {
|
||||||
|
console.log(data);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
method: 'GET'
|
||||||
|
, url: '/api/com.daplie.lex/sites'
|
||||||
|
}).then(function (data) {
|
||||||
|
var $hostnames = $('.js-hostnames');
|
||||||
|
$hostnames.html('');
|
||||||
|
data.forEach(function (config) {
|
||||||
|
var $conf = $(tpl);
|
||||||
|
$conf.text(config.domains);
|
||||||
|
$hostnames.append($conf);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,37 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Welcome to :hostname!</title>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
|
||||||
|
<meta http-equiv="Content-Security-Policy" content="default-src 'self';">
|
||||||
|
<link rel="stylesheet" type="text/css" href="./bootstrap.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<div class="jumbotron">
|
||||||
|
<h1>Add a Site</h1>
|
||||||
|
<form class="js-add-site">
|
||||||
|
<label>Domain</label>: <input type="text" class="js-domains" placeholder="ex: example.com,www.example.com">
|
||||||
|
<br/>
|
||||||
|
<label>Email</label>: <input type="email" class="js-email" placeholder="ex: user@example.com">
|
||||||
|
<br/>
|
||||||
|
<label>LE Server</label>: <input type="text" class="js-server" placeholder="ex: https://acme-staging.api.letsencrypt.org/directory" value="https://acme-v01.api.letsencrypt.org/directory">
|
||||||
|
<br/>
|
||||||
|
<label><input type="checkbox" class="js-agree-tos"> Agree to Let's Encrypt Terms of Service?</label>
|
||||||
|
<br/>
|
||||||
|
<button class="btn btn-primary" type="submit">Add Site</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<p>Sites:
|
||||||
|
<div class="js-hostnames-container">
|
||||||
|
<ul class="js-hostnames">
|
||||||
|
<li class="js-hostname"></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script src="./jquery.js"></script>
|
||||||
|
<script src="./app.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,24 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Welcome to :hostname!</title>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
|
||||||
|
<meta http-equiv="Content-Security-Policy" content="default-src 'self';">
|
||||||
|
<link rel="stylesheet" type="text/css" href="./bootstrap.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<div class="jumbotron">
|
||||||
|
<h1>Hello, world!</h1>
|
||||||
|
<p>Your website is located in one of two places:</p>
|
||||||
|
<ul>
|
||||||
|
<li>on your <code>Desktop</code> inside of the <code>www</code> directory and <code>:hostname</code></li>
|
||||||
|
<li><code>~/www/:hostname</code> (your home folder, under <code>www/:hostname</code></li>
|
||||||
|
<ul>
|
||||||
|
<p>This very file is called <code>index.html</code>.
|
||||||
|
You can open it up in <code>notepad</code> and change it up a little if you'd like.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script src="./jquery.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
22
package.json
22
package.json
|
@ -3,6 +3,16 @@
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"description": "Free SSL and Automatic HTTPS for node.js with Express, Connect, and other middleware systems",
|
"description": "Free SSL and Automatic HTTPS for node.js with Express, Connect, and other middleware systems",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
|
"bin": {
|
||||||
|
"letsencrypt-express": "bin/lex.js",
|
||||||
|
"lex": "bin/lex.js"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"lib/",
|
||||||
|
"bin/",
|
||||||
|
"examples/",
|
||||||
|
"index.js"
|
||||||
|
],
|
||||||
"directories": {
|
"directories": {
|
||||||
"example": "examples"
|
"example": "examples"
|
||||||
},
|
},
|
||||||
|
@ -33,9 +43,15 @@
|
||||||
"url": "https://github.com/Daplie/letsencrypt-express/issues"
|
"url": "https://github.com/Daplie/letsencrypt-express/issues"
|
||||||
},
|
},
|
||||||
"homepage": "https://github.com/Daplie/letsencrypt-express#readme",
|
"homepage": "https://github.com/Daplie/letsencrypt-express#readme",
|
||||||
"dependencies": {
|
"devDependencies": {
|
||||||
"homedir": "^0.6.0",
|
"body-parser": "^1.14.2",
|
||||||
"letsencrypt": "^1.3.0",
|
"cli": "^0.11.1",
|
||||||
|
"express": "^4.13.3",
|
||||||
|
"localhost.daplie.com-certificates": "^1.1.2",
|
||||||
"mkdirp": "^0.5.1"
|
"mkdirp": "^0.5.1"
|
||||||
}
|
}
|
||||||
|
"dependencies": {
|
||||||
|
"homedir": "^0.6.0",
|
||||||
|
"letsencrypt": "^1.3.0"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue