manage renewals perfectly :-)
This commit is contained in:
		
							parent
							
								
									a6b1b5cfa6
								
							
						
					
					
						commit
						563f3ae3eb
					
				
							
								
								
									
										7
									
								
								index.js
									
									
									
									
									
								
							
							
						
						
									
										7
									
								
								index.js
									
									
									
									
									
								
							| @ -137,8 +137,11 @@ LE.create = function (defaults, handlers, backend) { | |||||||
|       //  If you do not check these things, then someone could attack you
 |       //  If you do not check these things, then someone could attack you
 | ||||||
|       //  and cause you, in return, to have your ip be rate-limit blocked
 |       //  and cause you, in return, to have your ip be rate-limit blocked
 | ||||||
|       //
 |       //
 | ||||||
|       console.warn("\n[TODO]: node-letsencrypt: `validate(hostnames, cb)` needs to be implemented"); |       //console.warn("\n[TODO]: node-letsencrypt: `validate(hostnames, cb)` needs to be implemented");
 | ||||||
|       console.warn("(it'll work fine without it, but for security - and convenience - it should be implemented\n"); |       //console.warn("(it'll work fine without it, but for security - and convenience - it should be implemented\n");
 | ||||||
|  |       // UPDATE:
 | ||||||
|  |       // it's actually probably better that we don't do this here and instead
 | ||||||
|  |       // take care of it in the approveRegistrationCallback in letsencrypt-express
 | ||||||
|       cb(null, true); |       cb(null, true); | ||||||
|     } |     } | ||||||
|   , _registerHelper: function (args, cb) { |   , _registerHelper: function (args, cb) { | ||||||
|  | |||||||
| @ -72,7 +72,8 @@ function createAccount(args, handlers) { | |||||||
|   }); |   }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function getAccount(accountId, args, handlers) { | function getAccount(args, handlers) { | ||||||
|  |   var accountId = args.accountId; | ||||||
|   var accountDir = path.join(args.accountsDir, accountId); |   var accountDir = path.join(args.accountsDir, accountId); | ||||||
|   var files = {}; |   var files = {}; | ||||||
|   var configs = ['meta.json', 'private_key.json', 'regr.json']; |   var configs = ['meta.json', 'private_key.json', 'regr.json']; | ||||||
|  | |||||||
							
								
								
									
										242
									
								
								lib/core.js
									
									
									
									
									
								
							
							
						
						
									
										242
									
								
								lib/core.js
									
									
									
									
									
								
							| @ -31,23 +31,137 @@ function getAcmeUrls(args) { | |||||||
|   }); |   }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function writeCertificateAsync(result, args, defaults, handlers) { | function readRenewalConfig(args) { | ||||||
|  |   var pyconf = PromiseA.promisifyAll(require('pyconf')); | ||||||
|  | 
 | ||||||
|  |   return pyconf.readFileAsync(args.renewalPath).then(function (pyobj) { | ||||||
|  |     return pyobj; | ||||||
|  |   }, function () { | ||||||
|  |     return pyconf.readFileAsync(path.join(__dirname, 'renewal.conf.tpl')).then(function (pyobj) { | ||||||
|  |       return pyobj; | ||||||
|  |     }); | ||||||
|  |   }); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function writeRenewalConfig(args) { | ||||||
|  |   var pyobj = args.pyobj; | ||||||
|  |   pyobj.checkpoints = parseInt(pyobj.checkpoints, 10) || 0; | ||||||
|  | 
 | ||||||
|  |   var pyconf = PromiseA.promisifyAll(require('pyconf')); | ||||||
|  | 
 | ||||||
|  |   var liveDir = args.liveDir || path.join(args.configDir, 'live', args.domains[0]); | ||||||
|  | 
 | ||||||
|  |   var certPath = args.certPath || pyobj.cert || path.join(liveDir, 'cert.pem'); | ||||||
|  |   var fullchainPath = args.fullchainPath || pyobj.fullchain || path.join(liveDir, 'fullchain.pem'); | ||||||
|  |   var chainPath = args.chainPath || pyobj.chain || path.join(liveDir, 'chain.pem'); | ||||||
|  |   var privkeyPath = args.privkeyPath || pyobj.privkey | ||||||
|  |     //|| args.domainPrivateKeyPath || args.domainKeyPath || pyobj.keyPath
 | ||||||
|  |     || path.join(liveDir, 'privkey.pem'); | ||||||
|  | 
 | ||||||
|  |   if (args.debug) { | ||||||
|  |     console.log('################   privkeyPath   ################'); | ||||||
|  |     console.log(privkeyPath); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   var updates = { | ||||||
|  |     account: args.account.id | ||||||
|  |   , configDir: args.configDir | ||||||
|  |   , domains: args.domains | ||||||
|  | 
 | ||||||
|  |   , email: args.email | ||||||
|  |   , tos: args.agreeTos && true | ||||||
|  |     // yes, it's an array. weird, right?
 | ||||||
|  |   , webrootPath: args.webrootPath && [args.webrootPath] || [] | ||||||
|  |   , server: args.server || args.acmeDiscoveryUrl | ||||||
|  | 
 | ||||||
|  |   , privkey: privkeyPath | ||||||
|  |   , fullchain: fullchainPath | ||||||
|  |   , cert: certPath | ||||||
|  |   , chain: chainPath | ||||||
|  | 
 | ||||||
|  |   , http01Port: args.http01Port | ||||||
|  |   , keyPath: args.domainPrivateKeyPath || args.privkeyPath | ||||||
|  |   , rsaKeySize: args.rsaKeySize | ||||||
|  |   , checkpoints: pyobj.checkpoints | ||||||
|  |     /* // TODO XXX what's the deal with these? they don't make sense | ||||||
|  |     // are they just old junk? or do they have a meaning that I don't know about?
 | ||||||
|  |   , fullchainPath: path.join(args.configDir, 'chain.pem') | ||||||
|  |   , certPath: path.join(args.configDir, 'cert.pem') | ||||||
|  |   , chainPath: path.join(args.configDir, 'chain.pem') | ||||||
|  |     */ // TODO XXX end | ||||||
|  |   , workDir: args.workDir | ||||||
|  |   , logsDir: args.logsDir | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   // final section is completely dynamic
 | ||||||
|  |   // :hostname = :webroot_path
 | ||||||
|  |   args.domains.forEach(function (hostname) { | ||||||
|  |     updates[hostname] = args.webrootPath; | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|  |   // must write back to the original pyobject or
 | ||||||
|  |   // annotations will be lost
 | ||||||
|  |   Object.keys(updates).forEach(function (key) { | ||||||
|  |     pyobj[key] = updates[key]; | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|  |   return mkdirpAsync(path.dirname(args.renewalPath)).then(function () { | ||||||
|  |     return pyconf.writeFileAsync(args.renewalPath, pyobj); | ||||||
|  |   }).then(function () { | ||||||
|  |     return pyobj; | ||||||
|  |   }); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function getOrCreateRenewal(args) { | ||||||
|  |   return readRenewalConfig(args).then(function (pyobj) { | ||||||
|  |     var minver = pyobj.checkpoints >= 0; | ||||||
|  | 
 | ||||||
|  |     args.pyobj = pyobj; | ||||||
|  | 
 | ||||||
|  |     if (!minver) { | ||||||
|  |       args.checkpoints = 0; | ||||||
|  |       pyobj.checkpoints = 0; | ||||||
|  |       return writeRenewalConfig(args); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // args.account.id = pyobj.account
 | ||||||
|  |     // args.configDir = args.configDir || pyobj.configDir;
 | ||||||
|  | 
 | ||||||
|  |     args.checkpoints = pyobj.checkpoints; | ||||||
|  | 
 | ||||||
|  |     args.agreeTos = (args.agreeTos || pyobj.tos) && true; | ||||||
|  |     args.email = args.email || pyobj.email; | ||||||
|  |     args.domains = args.domains || pyobj.domains; | ||||||
|  | 
 | ||||||
|  |     // yes, it's an array. weird, right?
 | ||||||
|  |     args.webrootPath = args.webrootPath || pyobj.webrootPath[0]; | ||||||
|  |     args.server = args.server || args.acmeDiscoveryUrl || pyobj.server; | ||||||
|  | 
 | ||||||
|  |     args.certPath = args.certPath || pyobj.cert; | ||||||
|  |     args.privkeyPath = args.privkeyPath || pyobj.privkey; | ||||||
|  |     args.chainPath = args.chainPath || pyobj.chain; | ||||||
|  |     args.fullchainPath = args.fullchainPath || pyobj.fullchain; | ||||||
|  | 
 | ||||||
|  |   //, workDir: args.workDir
 | ||||||
|  |   //, logsDir: args.logsDir
 | ||||||
|  |     args.rsaKeySize = args.rsaKeySize || pyobj.rsaKeySize; | ||||||
|  |     args.http01Port = args.http01Port || pyobj.http01Port; | ||||||
|  |     args.domainKeyPath = args.domainPrivateKeyPath || args.domainKeyPath || args.keyPath || pyobj.keyPath; | ||||||
|  | 
 | ||||||
|  |     return writeRenewalConfig(args); | ||||||
|  |   }); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function writeCertificateAsync(args, defaults, handlers) { | ||||||
|   if (args.debug) { |   if (args.debug) { | ||||||
|     console.log("got certificate!"); |     console.log("got certificate!"); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   var obj = args.pyobj; | ||||||
|  |   var result = args.pems; | ||||||
|  | 
 | ||||||
|   result.fullchain = result.cert + '\n' + result.ca; |   result.fullchain = result.cert + '\n' + result.ca; | ||||||
| 
 |   obj.checkpoints = parseInt(obj.checkpoints, 10) || 0; | ||||||
|   var pyconf = PromiseA.promisifyAll(require('pyconf')); |  | ||||||
| 
 |  | ||||||
|   return pyconf.readFileAsync(args.renewalPath).then(function (obj) { |  | ||||||
|     return obj; |  | ||||||
|   }, function () { |  | ||||||
|     return pyconf.readFileAsync(path.join(__dirname, 'renewal.conf.tpl')).then(function (obj) { |  | ||||||
|       return obj; |  | ||||||
|     }); |  | ||||||
|   }).then(function (obj) { |  | ||||||
|     obj.checkpoint = parseInt(obj.checkpoint, 10) || 0; |  | ||||||
| 
 | 
 | ||||||
|   var liveDir = args.liveDir || path.join(args.configDir, 'live', args.domains[0]); |   var liveDir = args.liveDir || path.join(args.configDir, 'live', args.domains[0]); | ||||||
| 
 | 
 | ||||||
| @ -65,11 +179,11 @@ function writeCertificateAsync(result, args, defaults, handlers) { | |||||||
| 
 | 
 | ||||||
|   var archiveDir = args.archiveDir || path.join(args.configDir, 'archive', args.domains[0]); |   var archiveDir = args.archiveDir || path.join(args.configDir, 'archive', args.domains[0]); | ||||||
| 
 | 
 | ||||||
|     var checkpoint = obj.checkpoint.toString(); |   var checkpoints = obj.checkpoints.toString(); | ||||||
|     var certArchive = path.join(archiveDir, 'cert' + checkpoint + '.pem'); |   var certArchive = path.join(archiveDir, 'cert' + checkpoints + '.pem'); | ||||||
|     var fullchainArchive = path.join(archiveDir, 'fullchain' + checkpoint + '.pem'); |   var fullchainArchive = path.join(archiveDir, 'fullchain' + checkpoints + '.pem'); | ||||||
|     var chainArchive = path.join(archiveDir, 'chain'+ checkpoint + '.pem'); |   var chainArchive = path.join(archiveDir, 'chain'+ checkpoints + '.pem'); | ||||||
|     var privkeyArchive = path.join(archiveDir, 'privkey' + checkpoint + '.pem'); |   var privkeyArchive = path.join(archiveDir, 'privkey' + checkpoints + '.pem'); | ||||||
| 
 | 
 | ||||||
|   return mkdirpAsync(archiveDir).then(function () { |   return mkdirpAsync(archiveDir).then(function () { | ||||||
|     return PromiseA.all([ |     return PromiseA.all([ | ||||||
| @ -88,51 +202,10 @@ function writeCertificateAsync(result, args, defaults, handlers) { | |||||||
|     , sfs.writeFileAsync(privkeyPath, result.key || result.privkey || args.domainPrivateKeyPem, 'ascii') |     , sfs.writeFileAsync(privkeyPath, result.key || result.privkey || args.domainPrivateKeyPem, 'ascii') | ||||||
|     ]); |     ]); | ||||||
|   }).then(function () { |   }).then(function () { | ||||||
|       obj.checkpoint += 1; |     obj.checkpoints += 1; | ||||||
|  |     args.checkpoints += 1; | ||||||
| 
 | 
 | ||||||
|       var updates = { |     return writeRenewalConfig(args); | ||||||
|         account: args.accountId || args.account.id |  | ||||||
| 
 |  | ||||||
|       , cert: certPath |  | ||||||
|       , privkey: privkeyPath |  | ||||||
|       , chain: chainPath |  | ||||||
|       , fullchain: fullchainPath |  | ||||||
|       , configDir: args.configDir |  | ||||||
|       , workDir: args.workDir |  | ||||||
|       , tos: args.agreeTos && true |  | ||||||
|       , http01Port: args.http01Port |  | ||||||
|       , keyPath: args.domainPrivateKeyPath || args.privkeyPath |  | ||||||
|       , email: args.email |  | ||||||
|       , domains: args.domains |  | ||||||
|       , rsaKeySize: args.rsaKeySize |  | ||||||
|       , checkpoints: obj.checkpoint |  | ||||||
|         // TODO XXX what's the deal with these? they don't make sense
 |  | ||||||
|         // are they just old junk? or do they have a meaning that I don't know about?
 |  | ||||||
|       , fullchainPath: path.join(args.configDir, 'chain.pem') |  | ||||||
|       , certPath: path.join(args.configDir, 'cert.pem') |  | ||||||
|       , chainPath: path.join(args.configDir, 'chain.pem') |  | ||||||
|         // TODO XXX end
 |  | ||||||
|         // yes, it's an array. weird, right?
 |  | ||||||
|       , webrootPath: args.webrootPath && [args.webrootPath] || [] |  | ||||||
|       , server: args.server || args.acmeDiscoveryUrl |  | ||||||
|       , logsDir: args.logsDir |  | ||||||
|       }; |  | ||||||
| 
 |  | ||||||
|       // final section is completely dynamic
 |  | ||||||
|       // :hostname = :webroot_path
 |  | ||||||
|       args.domains.forEach(function (hostname) { |  | ||||||
|         updates[hostname] = args.webrootPath; |  | ||||||
|       }); |  | ||||||
| 
 |  | ||||||
|       // must write back to the original object or
 |  | ||||||
|       // annotations will be lost
 |  | ||||||
|       Object.keys(updates).forEach(function (key) { |  | ||||||
|         obj[key] = updates[key]; |  | ||||||
|       }); |  | ||||||
| 
 |  | ||||||
|       return mkdirpAsync(path.dirname(args.renewalPath)).then(function () { |  | ||||||
|         return pyconf.writeFileAsync(args.renewalPath, obj); |  | ||||||
|       }); |  | ||||||
|   }).then(function () { |   }).then(function () { | ||||||
| 
 | 
 | ||||||
|     return { |     return { | ||||||
| @ -152,10 +225,11 @@ function writeCertificateAsync(result, args, defaults, handlers) { | |||||||
|     , lifetime: defaults.lifetime || handlers.lifetime |     , lifetime: defaults.lifetime || handlers.lifetime | ||||||
|     }; |     }; | ||||||
|   }); |   }); | ||||||
|   }); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function getCertificateAsync(account, args, defaults, handlers) { | function getCertificateAsync(args, defaults, handlers) { | ||||||
|  |   var account = args.account; | ||||||
|  | 
 | ||||||
|   return leCrypto.generateRsaKeypairAsync(args.rsaKeySize, 65537).then(function (domainKey) { |   return leCrypto.generateRsaKeypairAsync(args.rsaKeySize, 65537).then(function (domainKey) { | ||||||
|     if (args.debug) { |     if (args.debug) { | ||||||
|       console.log("get certificate"); |       console.log("get certificate"); | ||||||
| @ -214,11 +288,12 @@ function getCertificateAsync(account, args, defaults, handlers) { | |||||||
|       } |       } | ||||||
|     }); |     }); | ||||||
|   }).then(function (results) { |   }).then(function (results) { | ||||||
|     return writeCertificateAsync(results, args, defaults, handlers); |     args.pems = results; | ||||||
|  |     return writeCertificateAsync(args, defaults, handlers); | ||||||
|   }); |   }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function getOrCreateDomainCertificate(account, args, defaults, handlers) { | function getOrCreateDomainCertificate(args, defaults, handlers) { | ||||||
|   return fetchFromConfigLiveDir(args).then(function (certs) { |   return fetchFromConfigLiveDir(args).then(function (certs) { | ||||||
|     // if nothing, register and save
 |     // if nothing, register and save
 | ||||||
|     // if something, check date (don't register unless 30+ days)
 |     // if something, check date (don't register unless 30+ days)
 | ||||||
| @ -228,15 +303,15 @@ function getOrCreateDomainCertificate(account, args, defaults, handlers) { | |||||||
|     //console.log(certs);
 |     //console.log(certs);
 | ||||||
|     if (!certs) { |     if (!certs) { | ||||||
|       // no certs, seems like a good time to get some
 |       // no certs, seems like a good time to get some
 | ||||||
|       return getCertificateAsync(account, args, defaults, handlers); |       return getCertificateAsync(args, defaults, handlers); | ||||||
|     } |     } | ||||||
|     else if (certs.issuedAt > (27 * 24 * 60 * 60 * 1000)) { |     else if (certs.issuedAt > (27 * 24 * 60 * 60 * 1000)) { | ||||||
|       // cert is at least 27 days old we can renew that
 |       // cert is at least 27 days old we can renew that
 | ||||||
|       return getCertificateAsync(account, args, defaults, handlers); |       return getCertificateAsync(args, defaults, handlers); | ||||||
|     } |     } | ||||||
|     else if (args.duplicate) { |     else if (args.duplicate) { | ||||||
|       // YOLO! I be gettin' fresh certs 'erday! Yo!
 |       // YOLO! I be gettin' fresh certs 'erday! Yo!
 | ||||||
|       return getCertificateAsync(account, args, defaults, handlers); |       return getCertificateAsync(args, defaults, handlers); | ||||||
|     } |     } | ||||||
|     else { |     else { | ||||||
|       console.warn('[WARN] Ignoring renewal attempt for certificate less than 27 days old. Use args.duplicate to force.'); |       console.warn('[WARN] Ignoring renewal attempt for certificate less than 27 days old. Use args.duplicate to force.'); | ||||||
| @ -244,16 +319,10 @@ function getOrCreateDomainCertificate(account, args, defaults, handlers) { | |||||||
|       return certs; |       return certs; | ||||||
|     } |     } | ||||||
|   }); |   }); | ||||||
| }; | } | ||||||
| 
 | 
 | ||||||
| function getOrCreateAcmeAccount(args, defaults, handlers) { | function getOrCreateAcmeAccount(args, defaults, handlers) { | ||||||
|   var pyconf = PromiseA.promisifyAll(require('pyconf')); |   var pyconf = PromiseA.promisifyAll(require('pyconf')); | ||||||
|   var server = args.server; |  | ||||||
|   var acmeHostname = require('url').parse(server).hostname; |  | ||||||
|   var configDir = args.configDir; |  | ||||||
| 
 |  | ||||||
|   args.renewalPath = args.renewalPath || path.join(configDir, 'renewal', args.domains[0] + '.conf'); |  | ||||||
|   args.accountsDir = args.accountsDir || path.join(configDir, 'accounts', acmeHostname, 'directory'); |  | ||||||
| 
 | 
 | ||||||
|   return pyconf.readFileAsync(args.renewalPath).then(function (renewal) { |   return pyconf.readFileAsync(args.renewalPath).then(function (renewal) { | ||||||
|     var accountId = renewal.account; |     var accountId = renewal.account; | ||||||
| @ -279,7 +348,8 @@ function getOrCreateAcmeAccount(args, defaults, handlers) { | |||||||
|         if (args.debug) { |         if (args.debug) { | ||||||
|           console.log('[LE] use account'); |           console.log('[LE] use account'); | ||||||
|         } |         } | ||||||
|         return Accounts.getAccount(accountId, args, handlers); |         args.accountId = accountId; | ||||||
|  |         return Accounts.getAccount(args, handlers); | ||||||
|       } else { |       } else { | ||||||
|         if (args.debug) { |         if (args.debug) { | ||||||
|           console.log('[LE] create account'); |           console.log('[LE] create account'); | ||||||
| @ -322,13 +392,25 @@ module.exports.create = function (defaults, handlers) { | |||||||
|       copy = merge(args, defaults); |       copy = merge(args, defaults); | ||||||
|       tplCopy(copy); |       tplCopy(copy); | ||||||
| 
 | 
 | ||||||
|       if (args.debug) { |       if (copy.debug) { | ||||||
|         console.log('[LE DEBUG] reg domains', args.domains); |         console.log('[LE DEBUG] reg domains', args.domains); | ||||||
|       } |       } | ||||||
|  | 
 | ||||||
|  |       var url = require('url'); | ||||||
|  |       var acmeLocation = url.parse(copy.server); | ||||||
|  |       var acmeHostpath = path.join(acmeLocation.hostname, acmeLocation.pathname); | ||||||
|  |       copy.renewalPath = copy.renewalPath || path.join(copy.configDir, 'renewal', copy.domains[0] + '.conf'); | ||||||
|  |       copy.accountsDir = copy.accountsDir || path.join(copy.configDir, 'accounts', acmeHostpath); | ||||||
|  | 
 | ||||||
|       return getOrCreateAcmeAccount(copy, defaults, handlers).then(function (account) { |       return getOrCreateAcmeAccount(copy, defaults, handlers).then(function (account) { | ||||||
|         console.log("account", account); |         //console.log("account", account);
 | ||||||
|         args.account = account; |         copy.account = account; | ||||||
|         return getOrCreateDomainCertificate(account, copy, defaults, handlers); | 
 | ||||||
|  |         return getOrCreateRenewal(copy).then(function (pyobj) { | ||||||
|  | 
 | ||||||
|  |           copy.pyobj = pyobj; | ||||||
|  |           return getOrCreateDomainCertificate(copy, defaults, handlers); | ||||||
|  |         }); | ||||||
|       }); |       }); | ||||||
|     } |     } | ||||||
|   , fetchAsync: function (args) { |   , fetchAsync: function (args) { | ||||||
|  | |||||||
| @ -40,7 +40,7 @@ authenticator = webroot | |||||||
| domains = :hostnames #comma,delimited,list | domains = :hostnames #comma,delimited,list | ||||||
| rsa_key_size = :rsa_key_size | rsa_key_size = :rsa_key_size | ||||||
| # starts at 0 and increments at every renewal | # starts at 0 and increments at every renewal | ||||||
| checkpoints = :checkpoint_count | checkpoints = -1 | ||||||
| manual_test_mode = False | manual_test_mode = False | ||||||
| apache = False | apache = False | ||||||
| cert_path = :cert_path | cert_path = :cert_path | ||||||
|  | |||||||
							
								
								
									
										50
									
								
								tests/pyconf-write.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								tests/pyconf-write.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,50 @@ | |||||||
|  | 'use strict'; | ||||||
|  | 
 | ||||||
|  | var PromiseA = require('bluebird'); | ||||||
|  | var pyconf = PromiseA.promisifyAll(require('pyconf')); | ||||||
|  | var mkdirpAsync = PromiseA.promisify(require('mkdirp')); | ||||||
|  | var path = require('path'); | ||||||
|  | 
 | ||||||
|  | pyconf.readFileAsync(path.join(__dirname, 'lib', 'renewal.conf.tpl')).then(function (obj) { | ||||||
|  |   var domains = ['example.com', 'www.example.com']; | ||||||
|  |   var webrootPath = '/tmp/www/example.com'; | ||||||
|  | 
 | ||||||
|  |   console.log(obj); | ||||||
|  | 
 | ||||||
|  |   var keys = obj.__keys; | ||||||
|  |   var lines = obj.__lines; | ||||||
|  | 
 | ||||||
|  |   obj.__keys = null; | ||||||
|  |   obj.__lines = null; | ||||||
|  | 
 | ||||||
|  |   var updates = { | ||||||
|  |     account: 'ACCOUNT_ID' | ||||||
|  | 
 | ||||||
|  |   , cert: 'CERT_PATH' | ||||||
|  |   , privkey: 'PRIVATEKEY_PATH' | ||||||
|  |   , configDir: 'CONFIG_DIR' | ||||||
|  |   , tos: true | ||||||
|  |   , http01Port: 80 | ||||||
|  |   , domains: domains | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   // final section is completely dynamic
 | ||||||
|  |   // :hostname = :webroot_path
 | ||||||
|  |   domains.forEach(function (hostname) { | ||||||
|  |     updates[hostname] = webrootPath; | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|  |   // must write back to the original object or
 | ||||||
|  |   // annotations will be lost
 | ||||||
|  |   Object.keys(updates).forEach(function (key) { | ||||||
|  |     obj[key] = updates[key]; | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|  |   var renewalPath = '/tmp/letsencrypt/renewal/example.com.conf'; | ||||||
|  |   return mkdirpAsync(path.dirname(renewalPath)).then(function () { | ||||||
|  |     console.log(obj); | ||||||
|  |     obj.__keys = keys; | ||||||
|  |     obj.__lines = lines; | ||||||
|  |     return pyconf.writeFileAsync(renewalPath, obj); | ||||||
|  |   }); | ||||||
|  | }); | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user