diff --git a/example/cert-store.js b/example/cert-store.js new file mode 100644 index 0000000..7dd568b --- /dev/null +++ b/example/cert-store.js @@ -0,0 +1,24 @@ +// It's good to have a place to store the certificates so you can, +// y'know, use them! :-) + +'use strict'; + +// you receive a hostname and must give back an object +// with a public cert chain and a private key + +var certCache = {}; +var certStore = { + set: function (hostname, certs, cb) { + certCache[hostname] = certs; + cb(null); + } +, get: function (hostname, cb) { + cb(null, certCache[hostname]); + } +, remove: function (hostname, cb) { + delete certCache[hostname]; + cb(null); + } +}; + +module.exports = certStore; diff --git a/example/letsencrypt.js b/example/letsencrypt.js new file mode 100644 index 0000000..895241e --- /dev/null +++ b/example/letsencrypt.js @@ -0,0 +1,68 @@ +'use strict'; + +var LeCore = require('letiny-core'); + +var email = process.argv[2] || 'user@example.com'; // CHANGE THIS +var domains = [process.argv[3] || 'example.com']; // CHANGE THIS + +var accountPrivateKeyPem = '...'; // leCrypto.generateRsaKeypair(bitLen, exp, cb) +var domainPrivateKeyPem = '...'; // (same) + +var challengeStore = require('./challenge-store'); +var certStore = require('cert-store'); +var serve = require('./serve'); + +LeCore.getAcmeUrls( + LeCore.stagingServerUrl // or choose LeCore.productionServerUrl +, function (err, urls) { + + LeCore.registerNewAccount( + { newRegUrl: urls.newReg + , email: email + , accountPrivateKeyPem: accountPrivateKeyPem + , agreeToTerms: function (tosUrl, done) { + // agree to these exact terms + + console.log('[tosUrl]'); + console.log(tosUrl); + done(null, tosUrl); + } + } + , function (err, regr) { + + // Note: you should save the registration + // record to disk (or db) + console.log('[regr]'); + console.log(regr); + + LeCore.getCertificate( + { domainPrivateKeyPem: domainPrivateKeyPem + , accountPrivateKeyPem: accountPrivateKeyPem + , setChallenge: challengeStore.set + , removeChallenge: challengeStore.remove + , domains: domains + } + , function (err, certs) { + + // Note: you should save certs to disk (or db) + certStore + + } + ); + + } + ); + + } +); + +// +// Setup the Server +// +serve.init({ + LeCore: LeCore + // needs a default key and cert chain, anything will do +, httpsOptions: require('localhost.daplie.com-certificates') +, challengeStore: challengeStore +, certStore: certStore +}); diff --git a/example/serve.js b/example/serve.js new file mode 100644 index 0000000..a232144 --- /dev/null +++ b/example/serve.js @@ -0,0 +1,69 @@ +// That will fail unless you have a webserver running on 80 and 443 (or 5001) +// to respond to `/.well-known/acme-challenge/xxxxxxxx` with the proper token +'use strict'; + +module.exports.init = function (deps) { + var tls = require('tls'); + var https = require('https'); + var http = require('http'); + + + var LeCore = deps.LeCore; + var httpsOptions = deps.httpsOptions; + var challengeStore = deps.challengeStore; + var certStore = deps.certStore; + + + // + // Challenge Handler + // + function acmeResponder(req, res) { + if (0 !== req.url.indexOf(LeCore.acmeChallengePrefix)) { + res.end('Hello World!'); + return; + } + + var key = req.url.slice(LeCore.acmeChallengePrefix.length); + + challengeStore.get(req.hostname, key, function (err, val) { + res.end(val || 'Error'); + }); + } + + + // + // SNI Cert Handler + // + function certGetter(hostname, cb) { + certStore.get(hostname, function (err, certs) { + if (!certs) { + cb(null, null); + return; + } + + // Note: you should cache this context in memory + // so that you aren't creating a new one every time + var context = tls.createSecureContext({ + cert: certs.cert + , key: certs.key + }); + + cb(null, context); + }); + } + + + // + // Server + // + httpsOptions.SNICallback = certGetter; + https.createServer(httpsOptions, acmeResponder).listen(443, function () { + console.log('Listening https on', this.address()); + }); + https.createServer(httpsOptions, acmeResponder).listen(5001, function () { + console.log('Listening https on', this.address()); + }); + http.createServer().listen(80, function () { + console.log('Listening http on', this.address()); + }); +};