getting closer...
This commit is contained in:
		
							parent
							
								
									0404a2743c
								
							
						
					
					
						commit
						91981120b4
					
				| @ -12,7 +12,7 @@ Usage | ||||
| ----- | ||||
| 
 | ||||
| ```bash | ||||
| npm install --save le-store-certbot | ||||
| npm install --save le-store-certbot@2.x | ||||
| ``` | ||||
| 
 | ||||
| ```bash | ||||
| @ -26,6 +26,8 @@ var leStore = require('le-store-certbot').create({ | ||||
| , workDir: require('homedir')() + '/letsencrypt/var/lib' | ||||
| , logsDir: require('homedir')() + '/letsencrypt/var/log' | ||||
| 
 | ||||
| , webrootPath: '~/letsencrypt/srv/www/:hostname/.well-known/acme-challenge' | ||||
| 
 | ||||
| , debug: false | ||||
| }); | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										573
									
								
								index.js
									
									
									
									
									
								
							
							
						
						
									
										573
									
								
								index.js
									
									
									
									
									
								
							| @ -5,98 +5,6 @@ var mkdirpAsync = PromiseA.promisify(require('mkdirp')); | ||||
| var path = require('path'); | ||||
| var fs = PromiseA.promisifyAll(require('fs')); | ||||
| var sfs = require('safe-replace'); | ||||
| var homeRe = new RegExp("^~(\\/|\\\|\\" + path.sep + ")"); | ||||
| 
 | ||||
| var fetchFromConfigLiveDir = function (args) { | ||||
|   // TODO NO HARD-CODED DEFAULTS
 | ||||
|   if (!args.fullchainPath || !args.privkeyPath || !args.certPath || !args.chainPath) { | ||||
|     console.warn("missing one or more of args.privkeyPath, args.fullchainPath, args.certPath, args.chainPath"); | ||||
|     console.warn("hard-coded conventional pathnames were for debugging and are not a stable part of the API"); | ||||
|   } | ||||
| 
 | ||||
|   //, fs.readFileAsync(fullchainPath, 'ascii')
 | ||||
|   // note: if this ^^ gets added back in, the arrays below must change
 | ||||
|   return PromiseA.all([ | ||||
|     fs.readFileAsync(args.privkeyPath, 'ascii')   // 0
 | ||||
|   , fs.readFileAsync(args.certPath, 'ascii')      // 1
 | ||||
|   , fs.readFileAsync(args.chainPath, 'ascii')     // 2
 | ||||
| 
 | ||||
|     // stat the file, not the link
 | ||||
|   , fs.statAsync(args.certPath)                   // 3
 | ||||
|   ]).then(function (arr) { | ||||
|     return { | ||||
|       key: arr[0]                           // privkey.pem
 | ||||
|     , privkey: arr[0]                       // privkey.pem
 | ||||
| 
 | ||||
|     , fullchain: arr[1] + '\n' + arr[2]     // fullchain.pem
 | ||||
|     , cert: arr[1]                          // cert.pem
 | ||||
|       /* | ||||
|     , issuedAt: arr[3].mtime.valueOf() | ||||
|     , expiresAt: arr[3].mtime.valueOf() + (90 * 24 * 60 * 60 * 100) | ||||
|       */ | ||||
| 
 | ||||
|     , chain: arr[2]                         // chain.pem
 | ||||
|     , ca: arr[2]                            // chain.pem
 | ||||
| 
 | ||||
|     , privkeyPath: args.privkeyPath | ||||
|     , fullchainPath: args.fullchainPath | ||||
|     , certPath: args.certPath | ||||
|     , chainPath: args.chainPath | ||||
|     }; | ||||
|   }, function (err) { | ||||
|     if (args.debug) { | ||||
|       console.error("[letsencrypt/lib/common.js] fetchFromDisk"); | ||||
|       console.error(err.stack); | ||||
|     } | ||||
|     return null; | ||||
|   }); | ||||
| }; | ||||
| 
 | ||||
| function getAccount(args) { | ||||
|   var accountId = args.accountId; | ||||
|   var accountDir = path.join(args.accountsDir, accountId); | ||||
|   var files = {}; | ||||
|   var configs = [ 'meta.json', 'private_key.json', 'regr.json' ]; | ||||
| 
 | ||||
|   return PromiseA.all(configs.map(function (filename) { | ||||
|     var keyname = filename.slice(0, -5); | ||||
| 
 | ||||
|     return fs.readFileAsync(path.join(accountDir, filename), 'utf8').then(function (text) { | ||||
|       var data; | ||||
| 
 | ||||
|       try { | ||||
|         data = JSON.parse(text); | ||||
|       } catch(e) { | ||||
|         files[keyname] = { error: e }; | ||||
|         return; | ||||
|       } | ||||
| 
 | ||||
|       files[keyname] = data; | ||||
|     }, function (err) { | ||||
|       files[keyname] = { error: err }; | ||||
|     }); | ||||
|   })).then(function () { | ||||
|     var err; | ||||
| 
 | ||||
|     if (!Object.keys(files).every(function (key) { | ||||
|       return !files[key].error; | ||||
|     }) || !files.private_key || !files.private_key.n) { | ||||
|       err = new Error("Account '" + accountId + "' was corrupt. No big deal (I think?). Creating a new one..."); | ||||
|       err.code = 'E_ACCOUNT_CORRUPT'; | ||||
|       err.data = files; | ||||
|       return PromiseA.reject(err); | ||||
|     } | ||||
| 
 | ||||
|     //files.private_key;
 | ||||
|     //files.regr;
 | ||||
|     //files.meta;
 | ||||
|     files.accountId = accountId;                  // preserve current account id
 | ||||
|     files.id = accountId; | ||||
|     files.keypair = { privateKeyJwk: files.private_key }; | ||||
| 
 | ||||
|     return files; | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| function getAccountIdByEmail(args) { | ||||
|   // If we read 10,000 account directories looking for
 | ||||
| @ -161,18 +69,6 @@ function getAccountIdByEmail(args) { | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| 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) { | ||||
|   function log() { | ||||
|     if (args.debug) { | ||||
| @ -248,137 +144,6 @@ function writeRenewalConfig(args) { | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| 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) { | ||||
|   function log() { | ||||
|     if (args.debug) { | ||||
|       console.log.apply(console, arguments); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   log("[le/core.js] got certificate!"); | ||||
| 
 | ||||
|   var obj = args.pyobj; | ||||
|   var pems = args.pems; | ||||
| 
 | ||||
|   pems.fullchain = pems.cert + '\n' + (pems.chain || pems.ca); | ||||
|   obj.checkpoints = parseInt(obj.checkpoints, 10) || 0; | ||||
| 
 | ||||
|   var liveDir = args.liveDir || path.join(args.configDir, 'live', args.domains[0]); | ||||
| 
 | ||||
|   var certPath = args.certPath || obj.cert || path.join(liveDir, 'cert.pem'); | ||||
|   var fullchainPath = args.fullchainPath || obj.fullchain || path.join(liveDir, 'fullchain.pem'); | ||||
|   var chainPath = args.chainPath || obj.chain || path.join(liveDir, 'chain.pem'); | ||||
|   var privkeyPath = args.privkeyPath || obj.privkey | ||||
|     //|| args.domainPrivateKeyPath || args.domainKeyPath || obj.keyPath
 | ||||
|     || path.join(liveDir, 'privkey.pem'); | ||||
| 
 | ||||
|   log('[le/core.js] privkeyPath', privkeyPath); | ||||
| 
 | ||||
|   var archiveDir = args.archiveDir || path.join(args.configDir, 'archive', args.domains[0]); | ||||
| 
 | ||||
|   var checkpoints = obj.checkpoints.toString(); | ||||
|   var certArchive = path.join(archiveDir, 'cert' + checkpoints + '.pem'); | ||||
|   var fullchainArchive = path.join(archiveDir, 'fullchain' + checkpoints + '.pem'); | ||||
|   var chainArchive = path.join(archiveDir, 'chain'+ checkpoints + '.pem'); | ||||
|   var privkeyArchive = path.join(archiveDir, 'privkey' + checkpoints + '.pem'); | ||||
| 
 | ||||
|   return mkdirpAsync(archiveDir).then(function () { | ||||
|     return PromiseA.all([ | ||||
|       sfs.writeFileAsync(certArchive, pems.cert, 'ascii') | ||||
|     , sfs.writeFileAsync(chainArchive, (pems.chain || pems.ca), 'ascii') | ||||
|     , sfs.writeFileAsync(fullchainArchive, pems.fullchain, 'ascii') | ||||
|     , sfs.writeFileAsync( | ||||
|         privkeyArchive | ||||
|         // TODO nix args.key, args.domainPrivateKeyPem ??
 | ||||
|       , (pems.privkey || pems.key) // || RSA.exportPrivatePem(args.domainKeypair)
 | ||||
|       , 'ascii' | ||||
|       ) | ||||
|     ]); | ||||
|   }).then(function () { | ||||
|     return mkdirpAsync(liveDir); | ||||
|   }).then(function () { | ||||
|     return PromiseA.all([ | ||||
|       sfs.writeFileAsync(certPath, pems.cert, 'ascii') | ||||
|     , sfs.writeFileAsync(chainPath, (pems.chain || pems.ca), 'ascii') | ||||
|     , sfs.writeFileAsync(fullchainPath, pems.fullchain, 'ascii') | ||||
|     , sfs.writeFileAsync( | ||||
|         privkeyPath | ||||
|         // TODO nix args.key, args.domainPrivateKeyPem ??
 | ||||
|       , (pems.privkey || pems.key) // || RSA.exportPrivatePem(args.domainKeypair)
 | ||||
|       , 'ascii' | ||||
|       ) | ||||
|     ]); | ||||
|   }).then(function () { | ||||
|     obj.checkpoints += 1; | ||||
|     args.checkpoints += 1; | ||||
| 
 | ||||
|     return writeRenewalConfig(args); | ||||
|   }).then(function () { | ||||
|     return { | ||||
|       certPath: certPath | ||||
|     , chainPath: chainPath | ||||
|     , fullchainPath: fullchainPath | ||||
|     , privkeyPath: privkeyPath | ||||
| 
 | ||||
|       // TODO nix keypair
 | ||||
|     , keypair: args.domainKeypair | ||||
| 
 | ||||
|       // TODO nix args.key, args.domainPrivateKeyPem ??
 | ||||
|       // some ambiguity here...
 | ||||
|     , privkey: (pems.privkey || pems.key) //|| RSA.exportPrivatePem(args.domainKeypair)
 | ||||
|     , fullchain: pems.fullchain || (pems.cert + '\n' + pems.chain) | ||||
|     , chain:  (pems.chain || pems.ca) | ||||
|       // especially this one... might be cert only, might be fullchain
 | ||||
|     , cert: pems.cert | ||||
| 
 | ||||
|       /* | ||||
|     , issuedAt: Date.now() | ||||
|     , expiresAt: Date.now() + (90 * 24 * 60 * 60 * 100) | ||||
|       */ | ||||
|     }; | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| function pyToJson(pyobj) { | ||||
|   if (!pyobj) { | ||||
|     return null; | ||||
| @ -415,20 +180,7 @@ var defaults = { | ||||
| module.exports.create = function (configs) { | ||||
|   var mergedConfigs; | ||||
| 
 | ||||
|   function getConfigAsync(copy) { | ||||
|     copy.domains = []; | ||||
| 
 | ||||
|     return readRenewalConfig(copy).then(function (pyobj) { | ||||
|       var exists = pyobj.checkpoints >= 0; | ||||
|       if (!exists) { | ||||
|         return null; | ||||
|       } | ||||
| 
 | ||||
|       return pyToJson(pyobj); | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   return { | ||||
|   var store = { | ||||
|     getDefaults: function () { | ||||
|       if (mergedConfigs) { | ||||
|         return configs; | ||||
| @ -443,47 +195,236 @@ module.exports.create = function (configs) { | ||||
|       mergedConfigs = configs; | ||||
|       return configs; | ||||
|     } | ||||
|   , getPrivatePemAsync: function (args) { | ||||
| 
 | ||||
|     //
 | ||||
|     // Certificates
 | ||||
|     //
 | ||||
|   , certificates: { | ||||
|       checkKeypairAsync: function (args) { | ||||
|         if (!args.domainKeyPath) { | ||||
|           return PromiseA.reject(new Error("missing options.domainKeyPath")); | ||||
|         } | ||||
| 
 | ||||
|         return fs.readFileAsync(args.domainKeyPath, 'ascii'); | ||||
|       } | ||||
|   , setPrivatePemAsync: function (args, keypair) { | ||||
|     , setKeypairAsync: function (args, keypair) { | ||||
|         return mkdirpAsync(path.dirname(args.domainKeyPath)).then(function () { | ||||
|           return fs.writeFileAsync(args.domainKeyPath, keypair.privateKeyPem, 'ascii').then(function () { | ||||
|             return keypair; | ||||
|           }); | ||||
|         }); | ||||
|       } | ||||
|   , setRegistrationAsync: function (args) { | ||||
|       return writeCertificateAsync(args); | ||||
|     , checkAsync: function (args) { | ||||
|         if (!args.fullchainPath || !args.privkeyPath || !args.certPath || !args.chainPath) { | ||||
|           return PromiseA.reject(new Error("missing one or more of privkeyPath, fullchainPath, certPath, chainPath from options")); | ||||
|         } | ||||
| 
 | ||||
|   , getRegistrationAsync: function (args) { | ||||
|       return fetchFromConfigLiveDir(args); | ||||
|     } | ||||
|   , getOrCreateRenewalAsync: function (args) { | ||||
|       return getOrCreateRenewal(args); | ||||
|     } | ||||
|   , getConfigAsync: getConfigAsync | ||||
|   , getConfigsAsync: function (copy) { | ||||
|       copy.domains = []; | ||||
|         //, fs.readFileAsync(fullchainPath, 'ascii')
 | ||||
|         // note: if this ^^ gets added back in, the arrays below must change
 | ||||
|         return PromiseA.all([ | ||||
|           fs.readFileAsync(args.privkeyPath, 'ascii')   // 0
 | ||||
|         , fs.readFileAsync(args.certPath, 'ascii')      // 1
 | ||||
|         , fs.readFileAsync(args.chainPath, 'ascii')     // 2
 | ||||
| 
 | ||||
|       return fs.readdirAsync(copy.renewalDir).then(function (nodes) { | ||||
|         nodes = nodes.filter(function (node) { | ||||
|           return /^[a-z0-9]+.*\.conf$/.test(node); | ||||
|           // stat the file, not the link
 | ||||
|         , fs.statAsync(args.certPath)                   // 3
 | ||||
|         ]).then(function (arr) { | ||||
|           return { | ||||
|             key: arr[0]                           // privkey.pem
 | ||||
|           , privkey: arr[0]                       // privkey.pem
 | ||||
| 
 | ||||
|             // TODO for haproxy
 | ||||
|           , fullchain: arr[1] + '\r\n' + arr[2]   // fullchain.pem
 | ||||
|           , cert: arr[1]                          // cert.pem
 | ||||
|             /* | ||||
|           , issuedAt: arr[3].mtime.valueOf() | ||||
|           , expiresAt: arr[3].mtime.valueOf() + (90 * 24 * 60 * 60 * 100) | ||||
|             */ | ||||
| 
 | ||||
|           , chain: arr[2]                         // chain.pem
 | ||||
|           , ca: arr[2]                            // chain.pem
 | ||||
| 
 | ||||
|           , privkeyPath: args.privkeyPath | ||||
|           , fullchainPath: args.fullchainPath | ||||
|           , certPath: args.certPath | ||||
|           , chainPath: args.chainPath | ||||
|           }; | ||||
|         }, function (err) { | ||||
|           if (args.debug) { | ||||
|             console.error("[le-store-certbot] certificates.check"); | ||||
|             console.error(err.stack); | ||||
|           } | ||||
|           return null; | ||||
|         }); | ||||
|       } | ||||
|     , setAsync: function (args) { | ||||
|         // TODO get config
 | ||||
|         var pyobj = args.pyobj; | ||||
|         var pems = args.pems; | ||||
| 
 | ||||
|         return PromiseA.all(nodes.map(function (node) { | ||||
|           copy.domains = [node.replace(/\.conf$/, '')]; | ||||
|           return getConfigAsync(copy); | ||||
|         // TODO for haproxy
 | ||||
|         pems.fullchain = pems.cert + '\r\n' + (pems.chain || pems.ca); | ||||
|         pyobj.checkpoints = parseInt(pyobj.checkpoints, 10) || 0; | ||||
| 
 | ||||
|         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'); | ||||
| 
 | ||||
|         var archiveDir = args.archiveDir || path.join(args.configDir, 'archive', args.domains[0]); | ||||
| 
 | ||||
|         var checkpoints = pyobj.checkpoints.toString(); | ||||
|         var certArchive = path.join(archiveDir, 'cert' + checkpoints + '.pem'); | ||||
|         var fullchainArchive = path.join(archiveDir, 'fullchain' + checkpoints + '.pem'); | ||||
|         var chainArchive = path.join(archiveDir, 'chain'+ checkpoints + '.pem'); | ||||
|         var privkeyArchive = path.join(archiveDir, 'privkey' + checkpoints + '.pem'); | ||||
| 
 | ||||
|         return mkdirpAsync(archiveDir).then(function () { | ||||
|           return PromiseA.all([ | ||||
|             sfs.writeFileAsync(certArchive, pems.cert, 'ascii') | ||||
|           , sfs.writeFileAsync(chainArchive, (pems.chain || pems.ca), 'ascii') | ||||
|           , sfs.writeFileAsync(fullchainArchive, pems.fullchain, 'ascii') | ||||
|           , sfs.writeFileAsync( | ||||
|               privkeyArchive | ||||
|               // TODO nix args.key, args.domainPrivateKeyPem ??
 | ||||
|             , (pems.privkey || pems.key) // || RSA.exportPrivatePem(args.domainKeypair)
 | ||||
|             , 'ascii' | ||||
|             ) | ||||
|           ]); | ||||
|         }).then(function () { | ||||
|           return mkdirpAsync(liveDir); | ||||
|         }).then(function () { | ||||
|           return PromiseA.all([ | ||||
|             sfs.writeFileAsync(certPath, pems.cert, 'ascii') | ||||
|           , sfs.writeFileAsync(chainPath, (pems.chain || pems.ca), 'ascii') | ||||
|           , sfs.writeFileAsync(fullchainPath, pems.fullchain, 'ascii') | ||||
|           , sfs.writeFileAsync( | ||||
|               privkeyPath | ||||
|               // TODO nix args.key, args.domainPrivateKeyPem ??
 | ||||
|             , (pems.privkey || pems.key) // || RSA.exportPrivatePem(args.domainKeypair)
 | ||||
|             , 'ascii' | ||||
|             ) | ||||
|           ]); | ||||
|         }).then(function () { | ||||
|           pyobj.checkpoints += 1; | ||||
|           args.checkpoints += 1; | ||||
| 
 | ||||
|           return writeRenewalConfig(args); | ||||
|         }).then(function () { | ||||
|           return { | ||||
|             certPath: certPath | ||||
|           , chainPath: chainPath | ||||
|           , fullchainPath: fullchainPath | ||||
|           , privkeyPath: privkeyPath | ||||
| 
 | ||||
|             // TODO nix keypair
 | ||||
|           , keypair: args.domainKeypair | ||||
| 
 | ||||
|             // TODO nix args.key, args.domainPrivateKeyPem ??
 | ||||
|             // some ambiguity here...
 | ||||
|           , privkey: (pems.privkey || pems.key) //|| RSA.exportPrivatePem(args.domainKeypair)
 | ||||
|           , fullchain: pems.fullchain || (pems.cert + pems.chain) | ||||
|           , chain:  (pems.chain || pems.ca) | ||||
|             // especially this one... might be cert only, might be fullchain
 | ||||
|           , cert: pems.cert | ||||
| 
 | ||||
|             /* | ||||
|           , issuedAt: Date.now() | ||||
|           , expiresAt: Date.now() + (90 * 24 * 60 * 60 * 100) | ||||
|             */ | ||||
|           }; | ||||
|         }); | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     //
 | ||||
|     // Accounts
 | ||||
|     //
 | ||||
|   , accounts: { | ||||
|       checkAsync: function (args) { | ||||
|         var promise; | ||||
|         var files = {}; | ||||
|         var accountId; | ||||
| 
 | ||||
|         if (args.accountId) { | ||||
|           promise = PromiseA.resolve(args.accountId); | ||||
|         } | ||||
|         else if (args.email) { | ||||
|           promise = getAccountIdByEmail(args); | ||||
|         } | ||||
|         else { | ||||
|           promise = PromiseA.reject(new Error("must provide accountId or email")); | ||||
|         } | ||||
| 
 | ||||
|         promise.then(function (_accountId) { | ||||
|           accountId = _accountId; | ||||
|           var accountDir = path.join(args.accountsDir, accountId); | ||||
|           var configs = [ 'meta.json', 'private_key.json', 'regr.json' ]; | ||||
| 
 | ||||
|           return PromiseA.all(configs.map(function (filename) { | ||||
|             var keyname = filename.slice(0, -5); | ||||
| 
 | ||||
|             return fs.readFileAsync(path.join(accountDir, filename), 'utf8').then(function (text) { | ||||
|               var data; | ||||
| 
 | ||||
|               try { | ||||
|                 data = JSON.parse(text); | ||||
|               } catch(e) { | ||||
|                 files[keyname] = { error: e }; | ||||
|                 return; | ||||
|               } | ||||
| 
 | ||||
|               files[keyname] = data; | ||||
|             }, function (err) { | ||||
|               files[keyname] = { error: err }; | ||||
|             }); | ||||
|           })); | ||||
|         }).then(function () { | ||||
|           var err; | ||||
| 
 | ||||
|           if (!Object.keys(files).every(function (key) { | ||||
|             return !files[key].error; | ||||
|           }) || !files.private_key || !files.private_key.n) { | ||||
|             err = new Error("Account '" + accountId + "' was corrupt. No big deal (I think?). Creating a new one..."); | ||||
|             err.code = 'E_ACCOUNT_CORRUPT'; | ||||
|             err.data = files; | ||||
|             return PromiseA.reject(err); | ||||
|           } | ||||
| 
 | ||||
|           //files.private_key;
 | ||||
|           //files.regr;
 | ||||
|           //files.meta;
 | ||||
|           files.accountId = accountId;                  // preserve current account id
 | ||||
|           files.id = accountId; | ||||
|           files.keypair = { privateKeyJwk: files.private_key }; | ||||
| 
 | ||||
|           return files; | ||||
|         }); | ||||
|       } | ||||
|   , fetchAsync: function (args) { | ||||
|       return fetchFromConfigLiveDir(args); | ||||
|     , registerAsync: function (args) { | ||||
|         // save to renewal / account dir ???
 | ||||
|           return getOrCreateRenewal(copy).then(function (pyobj) { | ||||
| 
 | ||||
|             copy.pyobj = pyobj; | ||||
|             return files; | ||||
|           }); | ||||
| 
 | ||||
|       } | ||||
|   , getAccountIdByEmailAsync: getAccountIdByEmail | ||||
|   , getAccountAsync: getAccount | ||||
|   , setAccountAsync: function (args, account) { | ||||
|     , getAsync: function (args) { | ||||
|         return store.accounts.checkAsync(args).then(function (account) { | ||||
|           if (!args.account) { | ||||
|             return store.accounts.registerAsync(args); | ||||
|           } | ||||
| 
 | ||||
|           //args.account = account;
 | ||||
|           return account; | ||||
|         }); | ||||
|       } | ||||
|     , setAsync: function (args, account) { | ||||
|         var isoDate = new Date().toISOString(); | ||||
|         var os = require("os"); | ||||
|         var localname = os.hostname(); | ||||
| @ -532,5 +473,91 @@ module.exports.create = function (configs) { | ||||
|           return PromiseA.reject(err); | ||||
|         }); | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     //
 | ||||
|     // Configs
 | ||||
|     //
 | ||||
|   , configs: { | ||||
|       checkAsync: function (copy) { | ||||
|         copy.domains = []; | ||||
| 
 | ||||
|         return store.configs._checkHelperAsync(copy).then(function (pyobj) { | ||||
|           var exists = pyobj.checkpoints >= 0; | ||||
|           if (!exists) { | ||||
|             return null; | ||||
|           } | ||||
| 
 | ||||
|           return pyToJson(pyobj); | ||||
|         }); | ||||
|       } | ||||
|     , _checkHelperAsync: function (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; | ||||
|           }); | ||||
|         }); | ||||
|       } | ||||
|     , getAsync: function (args) { | ||||
|         return store.configs._checkHelperAsync(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); | ||||
|         }); | ||||
|       } | ||||
|     , allAsync: function (copy) { | ||||
|         copy.domains = []; | ||||
| 
 | ||||
|         return fs.readdirAsync(copy.renewalDir).then(function (nodes) { | ||||
|           nodes = nodes.filter(function (node) { | ||||
|             return /^[a-z0-9]+.*\.conf$/.test(node); | ||||
|           }); | ||||
| 
 | ||||
|           return PromiseA.all(nodes.map(function (node) { | ||||
|             copy.domains = [node.replace(/\.conf$/, '')]; | ||||
|             return store.configs.getAsync(copy); | ||||
|           })); | ||||
|         }); | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|   }; | ||||
| 
 | ||||
|   return store; | ||||
| }; | ||||
|  | ||||
							
								
								
									
										68
									
								
								renewal.conf.tpl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								renewal.conf.tpl
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,68 @@ | ||||
| #cert = :config/live/:hostname/cert.pem | ||||
| cert = :cert_path | ||||
| privkey = :privkey_path | ||||
| chain = :chain_path | ||||
| fullchain = :fullchain_path | ||||
| 
 | ||||
| # Options and defaults used in the renewal process | ||||
| [renewalparams] | ||||
| apache_enmod = a2enmod | ||||
| no_verify_ssl = False | ||||
| ifaces = None | ||||
| apache_dismod = a2dismod | ||||
| register_unsafely_without_email = False | ||||
| uir = None | ||||
| installer = none | ||||
| config_dir = :config | ||||
| text_mode = True | ||||
| # junk? | ||||
| # https://github.com/letsencrypt/letsencrypt/issues/1955 | ||||
| func = <function obtain_cert at 0x30c9500> | ||||
| prepare = False | ||||
| work_dir = :work_dir | ||||
| tos = :agree_tos | ||||
| init = False | ||||
| http01_port = :http_01_port | ||||
| duplicate = False | ||||
| # this is for the domain | ||||
| key_path = :privkey_path | ||||
| nginx = False | ||||
| fullchain_path = :fullchain_path | ||||
| email = :email | ||||
| csr = None | ||||
| agree_dev_preview = None | ||||
| redirect = None | ||||
| verbose_count = -3 | ||||
| config_file = None | ||||
| renew_by_default = True | ||||
| hsts = False | ||||
| authenticator = webroot | ||||
| domains = :hostnames #comma,delimited,list | ||||
| rsa_key_size = :rsa_key_size | ||||
| # 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 | ||||
| strict_permissions = False | ||||
| apache_server_root = /etc/apache2 | ||||
| # https://github.com/letsencrypt/letsencrypt/issues/1948 | ||||
| account = :account_id | ||||
| manual_public_ip_logging_ok = False | ||||
| chain_path = :chain_path | ||||
| standalone = False | ||||
| manual = False | ||||
| server = :acme_discovery_url | ||||
| standalone_supported_challenges = "http-01,tls-sni-01" | ||||
| webroot = True | ||||
| 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 | ||||
| configurator = None | ||||
| [[webroot_map]] | ||||
| # :hostname = :webroot_path | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user