diff --git a/README.md b/README.md index fb8611f..2f547cb 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,8 @@ le-store-certbot ================ -The "certbot" storage strategy for node-letsencrypt. +The "certbot" storage strategy for +[Greenlock.js](https://git.coolaj86.com/coolaj86/le-store-certbot.js). This le storage strategy aims to maintain compatibility with the configuration files and file structure of the official certbot client. @@ -17,24 +18,28 @@ npm install --save le-store-certbot@2.x ```bash var leStore = require('le-store-certbot').create({ - configDir: require('homedir')() + '/letsencrypt/etc' // or /etc/letsencrypt or wherever + configDir: require('homedir')() + '/acme/etc' // or /etc/acme or wherever , privkeyPath: ':configDir/live/:hostname/privkey.pem' // , fullchainPath: ':configDir/live/:hostname/fullchain.pem' // Note: both that :configDir and :hostname , certPath: ':configDir/live/:hostname/cert.pem' // will be templated as expected by -, chainPath: ':configDir/live/:hostname/chain.pem' // node-letsencrypt +, chainPath: ':configDir/live/:hostname/chain.pem' // greenlock.js -, workDir: require('homedir')() + '/letsencrypt/var/lib' -, logsDir: require('homedir')() + '/letsencrypt/var/log' +, workDir: require('homedir')() + '/acme/var/lib' +, logsDir: require('homedir')() + '/acme/var/log' -, webrootPath: '~/letsencrypt/srv/www/:hostname/.well-known/acme-challenge' +, webrootPath: '~/acme/srv/www/:hostname/.well-known/acme-challenge' , debug: false }); +``` -var LE = require('letsencrypt'); +The store module can be used globally with Greenlock like this: -LE.create({ - server: LE.stagingServerUrl // Change to LE.productionServerUrl in production +``` +var Greenlock = require('greenlock'); + +Greenlock.create({ + ... , store: leStore }); ``` @@ -43,7 +48,7 @@ Example File Structure ---------------------- ``` -~/letsencrypt/ +~/acme/ └── etc ├── accounts │   └── acme-staging.api.letsencrypt.org @@ -53,19 +58,19 @@ Example File Structure │   ├── private_key.json │   └── regr.json ├── archive - │   └── example.daplie.me + │   └── example.com │   ├── cert0.pem │   ├── chain0.pem │   ├── fullchain0.pem │   └── privkey0.pem ├── live - │   └── example.daplie.me + │   └── example.com │   ├── cert.pem │   ├── chain.pem │   ├── fullchain.pem │   ├── privkey.pem │   └── privkey.pem.bak └── renewal - ├── example.daplie.me.conf - └── example.daplie.me.conf.bak + ├── example.com.conf + └── example.com.conf.bak ``` diff --git a/index.js b/index.js index bbdfcee..1580df1 100644 --- a/index.js +++ b/index.js @@ -6,6 +6,7 @@ var path = require('path'); var fs = PromiseA.promisifyAll(require('fs')); var sfs = require('safe-replace'); var os = require('os'); +var symlink = require('fs-symlink'); function log(debug) { if (debug) { @@ -267,10 +268,10 @@ module.exports.create = function (configs) { return mkdirpAsync(liveDir); }).then(function () { return PromiseA.all([ - sfs.writeFileAsync(certPath, pems.cert, 'ascii') - , sfs.writeFileAsync(chainPath, pems.chain, 'ascii') - , sfs.writeFileAsync(fullchainPath, pems.cert + pems.chain, 'ascii') - , sfs.writeFileAsync(privkeyPath, pems.privkey, 'ascii') + symlink(certArchive, certPath) + , symlink(chainArchive, chainPath) + , symlink(fullchainArchive, fullchainPath) + , symlink(privkeyArchive, privkeyPath) ]); }).then(function () { pyobj.checkpoints += 1; @@ -373,7 +374,8 @@ module.exports.create = function (configs) { // Accounts , _getAccountIdByPublicKey: function (keypair) { // we use insecure md5 - even though we know it's bad - because that's how the python client did - return require('crypto').createHash('md5').update(keypair.publicKeyPem).digest('hex'); + const pubkey = keypair.publicKeyPem.replace(/\r/g, ''); + return require('crypto').createHash('md5').update(pubkey).digest('hex'); } // Accounts , checkKeypairAsync: function (args) { @@ -481,6 +483,8 @@ module.exports.create = function (configs) { creation_host: os.hostname() , creation_dt: new Date().toISOString() }; + var uri = args.server.replace(/\/directory.*/, + '/acme/reg/' + accountId); return mkdirpAsync(accountDir).then(function () { @@ -499,7 +503,9 @@ module.exports.create = function (configs) { new_authzr_uri: 'https://acme-v01.api.letsencrypt.org/acme/new-authz', terms_of_service: 'https://letsencrypt.org/documents/LE-SA-v1.0.1-July-27-2015.pdf' } */ - , fs.writeFileAsync(path.join(accountDir, 'regr.json'), JSON.stringify({ body: reg.receipt }), 'utf8') + , fs.writeFileAsync(path.join(accountDir, 'regr.json'), + JSON.stringify({ body: reg.receipt, uri: uri }), + 'utf8') ]); }).then(function () { return { diff --git a/package.json b/package.json index 4d0ddfa..ed122ce 100644 --- a/package.json +++ b/package.json @@ -1,14 +1,14 @@ { "name": "le-store-certbot", - "version": "2.0.5", - "description": "The \"certbot\" storage strategy for node-letsencrypt", + "version": "2.1.0", + "description": "The \"certbot\" storage strategy for Greenlock.js", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "repository": { "type": "git", - "url": "git+https://github.com/Daplie/le-store-certbot.git" + "url": "https://git.coolaj86.com/coolaj86/le-store-certbot.js" }, "keywords": [ "le-store", @@ -20,11 +20,12 @@ "author": "AJ ONeal (https://coolaj86.com/)", "license": "(MIT OR Apache-2.0)", "bugs": { - "url": "https://github.com/Daplie/le-store-certbot/issues" + "url": "https://git.coolaj86.com/coolaj86/le-store-certbot.js/issues" }, - "homepage": "https://github.com/Daplie/le-store-certbot#readme", + "homepage": "https://git.coolaj86.com/coolaj86/le-store-certbot.js", "dependencies": { - "bluebird": "^3.4.1", + "bluebird": "^3.5.1", + "fs-symlink": "^1.2.1", "mkdirp": "^0.5.1", "pyconf": "^1.1.2", "safe-replace": "^1.0.2" diff --git a/renewal.conf.tpl b/renewal.conf.tpl index 317e167..653d38d 100644 --- a/renewal.conf.tpl +++ b/renewal.conf.tpl @@ -6,63 +6,78 @@ fullchain = :fullchain_path # Options and defaults used in the renewal process [renewalparams] +no_self_upgrade = True apache_enmod = a2enmod no_verify_ssl = False ifaces = None apache_dismod = a2dismod register_unsafely_without_email = False +apache_handle_modules = True uir = None -installer = none +installer = None +nginx_ctl = nginx config_dir = :configDir text_mode = True # junk? # https://github.com/letsencrypt/letsencrypt/issues/1955 -func = +func = +staging = False prepare = False work_dir = :work_dir tos = :agree_tos init = False http01_port = :http_01_port duplicate = False +noninteractive_mode = True # this is for the domain key_path = :privkey_path nginx = False +nginx_server_root = /etc/nginx fullchain_path = :fullchain_path email = :email csr = None agree_dev_preview = None redirect = None +verb = certonly verbose_count = -3 config_file = None renew_by_default = True hsts = False +apache_handle_sites = True authenticator = webroot domains = :hostnames #comma,delimited,list rsa_key_size = :rsa_key_size +apache_challenge_location = /etc/apache2 # starts at 0 and increments at every renewal checkpoints = -1 manual_test_mode = False apache = False cert_path = :cert_path webroot_path = :webroot_paths # comma,delimited,list +reinstall = False +expand = False strict_permissions = False apache_server_root = /etc/apache2 # https://github.com/letsencrypt/letsencrypt/issues/1948 account = :account_id +dry_run = False manual_public_ip_logging_ok = False chain_path = :chain_path +break_my_certs = False standalone = False manual = False server = :acme_discovery_url standalone_supported_challenges = "http-01,tls-sni-01" webroot = True +os_packages_only = False apache_init_script = None user_agent = None -apache_ctl = apache2ctl apache_le_vhost_ext = -le-ssl.conf debug = False tls_sni_01_port = 443 logs_dir = :logs_dir +apache_vhost_root = /etc/apache2/sites-available configurator = None +must_staple = True [[webroot_map]] # :hostname = :webroot_path