express server läuft jetzt mit https
This commit is contained in:
Lukas Nowy
2018-12-16 19:08:08 +01:00
parent 5589b0df3f
commit fd947bd852
475 changed files with 91128 additions and 0 deletions

21
express-server/node_modules/le-store-certbot/LICENSE generated vendored Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2016 Daplie, Inc
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

75
express-server/node_modules/le-store-certbot/README.md generated vendored Normal file
View File

@ -0,0 +1,75 @@
le-store-certbot
================
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.
Note: You cannot use this strategy on ephemeral instances (heroku, aws elastic).
Usage
-----
```bash
npm install --save le-store-certbot@2.x
```
```bash
var leStore = require('le-store-certbot').create({
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' // greenlock.js
, logsDir: require('homedir')() + '/tmp/acme/log'
, webrootPath: '~/acme/srv/www/:hostname/.well-known/acme-challenge'
, debug: false
});
```
The store module can be used globally with Greenlock like this:
```
var Greenlock = require('greenlock');
Greenlock.create({
...
, store: leStore
});
```
Example File Structure
----------------------
```
~/acme/
└── etc
├── accounts
│   └── acme-staging.api.letsencrypt.org
│   └── directory
│   └── cd96ac4889ddfa47bfc66300ab223342
│   ├── meta.json
│   ├── private_key.json
│   └── regr.json
├── archive
│   └── example.com
│   ├── cert0.pem
│   ├── chain0.pem
│   ├── fullchain0.pem
│   └── privkey0.pem
├── live
│   └── example.com
│   ├── cert.pem
│   ├── chain.pem
│   ├── fullchain.pem
│   ├── privkey.pem
│   └── privkey.pem.bak
└── renewal
├── example.com.conf
└── example.com.conf.bak
```

661
express-server/node_modules/le-store-certbot/index.js generated vendored Normal file
View File

@ -0,0 +1,661 @@
'use strict';
/* global Promise */
var PromiseA;
try {
PromiseA = require('bluebird');
} catch(e) {
PromiseA = Promise;
}
var util = require('util');
function promisifyAll(obj) {
var aobj = {};
Object.keys(obj).forEach(function (key) {
aobj[key + 'Async'] = util.promisify(obj[key]);
});
return aobj;
}
var mkdirpAsync = util.promisify(require('mkdirp'));
var path = require('path');
var fs = require('fs');
var readFileAsync = util.promisify(fs.readFile);
var readdirAsync = util.promisify(fs.readdir);
var writeFileAsync = util.promisify(fs.writeFile);
var statAsync = util.promisify(fs.stat);
var sfs = require('safe-replace');
var os = require('os');
function log(debug) {
if (debug) {
var args = Array.prototype.slice.call(arguments);
args.shift();
args.unshift("[le-store-certbot]");
console.log.apply(console, args);
}
}
function writeRenewalConfig(args) {
var pyobj = args.pyobj;
pyobj.checkpoints = parseInt(pyobj.checkpoints, 10) || 0;
var pyconf = 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');
log(args.debug, 'writeRenewalConfig privkeyPath', 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 () {
// NOTE
// writing twice seems to causes a bug,
// so instead we re-read the file from the disk
return pyconf.readFileAsync(args.renewalPath);
});
}
function pyToJson(pyobj) {
if (!pyobj) {
return null;
}
var jsobj = {};
Object.keys(pyobj).forEach(function (key) {
jsobj[key] = pyobj[key];
});
jsobj.__lines = undefined;
jsobj.__keys = undefined;
return jsobj;
}
var crypto = require('crypto');
var rnd = crypto.randomBytes(8).toString('hex');
var defaults = {
configDir: [ os.homedir(), 'letsencrypt', 'etc' ].join(path.sep) // /etc/letsencrypt/
, logsDir: [ os.tmpdir(), 'acme-' + rnd, 'log' ].join(path.sep) // /var/log/letsencrypt/
, webrootPath: [ os.tmpdir(), 'acme-' + rnd, 'acme-challenge' ].join(path.sep)
, accountsDir: [ ':configDir', 'accounts', ':serverDir' ].join(path.sep)
, renewalPath: [ ':configDir', 'renewal', ':hostname.conf' ].join(path.sep)
, renewalDir: [ ':configDir', 'renewal', '' ].join(path.sep)
, serverDirGet: function (copy) {
return (copy.server || '').replace('https://', '').replace(/(\/)$/, '').replace(/\//g, path.sep);
}
, privkeyPath: ':configDir/live/:hostname/privkey.pem'.split(/\//).join(path.sep)
, fullchainPath: [ ':configDir', 'live', ':hostname', 'fullchain.pem' ].join(path.sep)
, certPath: [ ':configDir', 'live', ':hostname', 'cert.pem' ].join(path.sep)
, chainPath: [ ':configDir', 'live', ':hostname', 'chain.pem' ].join(path.sep)
, bundlePath: [ ':configDir', 'live', ':hostname', 'bundle.pem' ].join(path.sep)
, rsaKeySize: 2048
};
module.exports.create = function (configs) {
var mergedConfigs;
var store = {
getOptions: function () {
if (mergedConfigs) {
return configs;
}
if (!configs.domainKeyPath) {
configs.domainKeyPath = configs.privkeyPath || defaults.privkeyPath;
}
Object.keys(defaults).forEach(function (key) {
if (!configs[key]) {
configs[key] = defaults[key];
}
});
mergedConfigs = configs;
return configs;
}
, keypairs: {
checkAsync: function (keypath, format) {
if (!keypath) {
return null;
}
return readFileAsync(keypath, 'ascii').then(function (key) {
if ('jwk' === format) {
return { privateKeyJwk: JSON.parse(key) };
}
else {
return { privateKeyPem: key };
}
}, function (err) {
if ('ENOENT' !== err.code) {
throw err;
}
return null;
});
}
, setAsync: function (keypath, keypair, format) {
return mkdirpAsync(path.dirname(keypath)).then(function () {
var key;
if ('jwk' === format) {
key = JSON.stringify(keypair.privateKeyJwk, null, ' ');
}
else {
key = keypair.privateKeyPem;
}
return writeFileAsync(keypath, key, 'ascii').then(function () {
return keypair;
});
});
}
}
//
// Certificates
//
, certificates: {
// Certificates
checkKeypairAsync: function (args) {
if (!args.domainKeyPath) {
return PromiseA.reject(new Error("missing options.domainKeyPath"));
}
return store.keypairs.checkAsync(args.domainKeyPath, 'pem');
}
// Certificates
, setKeypairAsync: function (args, keypair) {
return store.keypairs.setAsync(args.domainKeyPath, keypair, 'pem');
}
// Certificates
, 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"));
}
//, readFileAsync(fullchainPath, 'ascii')
// note: if this ^^ gets added back in, the arrays below must change
return PromiseA.all([
readFileAsync(args.privkeyPath, 'ascii') // 0
, readFileAsync(args.certPath, 'ascii') // 1
, readFileAsync(args.chainPath, 'ascii') // 2
// stat the file, not the link
, statAsync(args.certPath) // 3
]).then(function (arr) {
return {
privkey: arr[0] // privkey.pem
, cert: arr[1] // cert.pem
, chain: arr[2] // chain.pem
/*
// TODO populate these values only if they are known
, issuedAt: arr[3].mtime.valueOf()
, expiresAt: arr[3].mtime.valueOf() + (90 * 24 * 60 * 60 * 100)
*/
};
}, function (err) {
if (args.debug) {
log("certificates.check");
log(err.stack);
}
return null;
});
}
// Certificates
, setAsync: function (args) {
return store.configs.getAsync(args).then(function (pyobj) {
var pems = args.pems;
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.domainKeyPath || path.join(liveDir, 'privkey.pem');
var bundlePath = args.bundlePath || pyobj.bundle || path.join(liveDir, 'bundle.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');
var bundleArchive = path.join(archiveDir, 'bundle' + checkpoints + '.pem');
return mkdirpAsync(archiveDir).then(function () {
return PromiseA.all([
sfs.writeFileAsync(certArchive, pems.cert, 'ascii')
, sfs.writeFileAsync(chainArchive, pems.chain, 'ascii')
, sfs.writeFileAsync(fullchainArchive, [ pems.cert, pems.chain ].join('\n'), 'ascii')
, sfs.writeFileAsync(privkeyArchive, pems.privkey, 'ascii')
, sfs.writeFileAsync(bundleArchive, pems.bundle, 'ascii')
]);
}).then(function () {
return mkdirpAsync(liveDir);
}).then(function () {
return PromiseA.all([
sfs.writeFileAsync(certPath, pems.cert, 'ascii')
, sfs.writeFileAsync(chainPath, pems.chain, 'ascii')
// Most platforms need these two
, sfs.writeFileAsync(fullchainPath, [ pems.cert, pems.chain ].join('\n'), 'ascii')
, sfs.writeFileAsync(privkeyPath, pems.privkey, 'ascii')
// HAProxy needs "bundle.pem" aka "combined.pem"
, sfs.writeFileAsync(bundlePath, [ pems.privkey, pems.cert, pems.chain ].join('\n'), 'ascii')
]);
}).then(function () {
pyobj.checkpoints += 1;
args.checkpoints += 1;
// TODO other than for compatibility this is optional, right?
// or is it actually needful for renewal? (i.e. list of domains)
return writeRenewalConfig(args);
}).then(function () {
return {
privkey: pems.privkey
, cert: pems.cert
, chain: pems.chain
, expires: pems.expires
, identifiers: pems.identifiers
/*
// TODO populate these only if they are actually known
, issuedAt: Date.now()
, expiresAt: Date.now() + (90 * 24 * 60 * 60 * 100)
*/
};
});
});
}
}
//
// Accounts
//
, accounts: {
// Accounts
_getAccountKeyPath: function (args) {
var promise = PromiseA.resolve(args.accountId);
if (args.email && !args.accountKeyPath && !args.accountId) {
promise = store.accounts._getAccountIdByEmail(args);
}
return promise.then(function (accountId) {
if (!accountId) {
return null;
}
return args.accountKeyPath || path.join(args.accountsDir, accountId, 'private_key.json');
});
}
// Accounts
, _getAccountIdByEmail: function (args) {
// If we read 10,000 account directories looking for
// just one email address, that could get crazy.
// We should have a folder per email and list
// each account as a file in the folder
// TODO
var email = args.email;
if ('string' !== typeof email) {
log(args.debug, "No email given");
return PromiseA.resolve(null);
}
return readdirAsync(args.accountsDir).then(function (nodes) {
log(args.debug, "success reading arg.accountsDir");
return PromiseA.all(nodes.map(function (node) {
return readFileAsync(path.join(args.accountsDir, node, 'regr.json'), 'utf8').then(function (text) {
var regr = JSON.parse(text);
regr.__accountId = node;
return regr;
});
})).then(function (regrs) {
var accountId;
log(args.debug, "regrs.length", regrs.length);
regrs.some(function (regr) {
return regr.body.contact.some(function (contact) {
var match = contact.toLowerCase() === 'mailto:' + email.toLowerCase();
if (match) {
accountId = regr.__accountId;
return true;
}
});
});
if (!accountId) {
return null;
}
return accountId;
});
}).then(function (accountId) {
return accountId;
}, function (err) {
if ('ENOENT' === err.code) {
// ignore error
return null;
}
return PromiseA.reject(err);
});
}
// Accounts
, _getAccountIdByPublicKey: function (keypair) {
// we use insecure md5 - even though we know it's bad - because that's how the python client did
var pubkey = keypair.publicKeyPem.replace(/\r/g, '');
return crypto.createHash('md5').update(pubkey).digest('hex');
}
// Accounts
, checkKeypairAsync: function (args) {
if (!(args.accountKeyPath || args.accountsDir)) {
return PromiseA.reject(new Error("must provide one of options.accountKeyPath or options.accountsDir"));
}
return store.accounts._getAccountKeyPath(args).then(function (keypath) {
return store.keypairs.checkAsync(keypath, 'jwk');
});
}
// Accounts
, setKeypairAsync: function (args, keypair) {
var accountId;
if (args.email) {
accountId = store.accounts._getAccountIdByPublicKey(keypair);
}
return store.accounts._getAccountKeyPath({
accountsDir: args.accountsDir
, email: args.email
, accountId: args.accountId || accountId
}).then(function (keypath) {
return store.keypairs.setAsync(keypath, keypair, 'jwk');
});
}
// Accounts
, checkAsync: function (args) {
var promise;
var files = {};
var accountId;
if (args.accountId) {
promise = PromiseA.resolve(args.accountId);
}
else if (args.email) {
promise = store.accounts._getAccountIdByEmail(args);
}
else {
promise = PromiseA.reject(new Error("must provide accountId or email"));
}
return promise.then(function (_accountId) {
log(args.debug, 'accountId:', _accountId);
if (!_accountId) {
return false;
}
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 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;
return true;
}, function (err) {
log(args.debug, 'Error reading account files:', err);
files[keyname] = { error: err };
});
}));
}).then(function (hasAccount) {
if (!hasAccount) {
return null;
}
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 (had id, but was missing files).");
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;
});
}
// Accounts
, setAsync: function (args, reg) {
var os = require("os");
var accountId = store.accounts._getAccountIdByPublicKey(reg.keypair);
var accountDir = path.join(args.accountsDir, accountId);
var accountMeta = {
creation_host: os.hostname()
, creation_dt: new Date().toISOString()
};
var uri = args.server.replace(/\/directory.*/,
'/acme/reg/' + accountId);
return mkdirpAsync(accountDir).then(function () {
var regrBody = {
body: reg.receipt,
uri: uri,
};
if (typeof reg.newAuthzUrl !== 'undefined') {
regrBody.new_authzr_uri = reg.newAuthzUrl;
}
// TODO abstract file writing
return PromiseA.all([
// meta.json {"creation_host": "ns1.redirect-www.org", "creation_dt": "2015-12-11T04:14:38Z"}
writeFileAsync(path.join(accountDir, 'meta.json'), JSON.stringify(accountMeta), 'utf8')
// private_key.json { "e", "d", "n", "q", "p", "kty", "qi", "dp", "dq" }
, writeFileAsync(path.join(accountDir, 'private_key.json'), JSON.stringify(reg.keypair.privateKeyJwk), 'utf8')
// regr.json:
/*
{ body: { contact: [ 'mailto:coolaj86@gmail.com' ],
agreement: 'https://letsencrypt.org/documents/LE-SA-v1.0.1-July-27-2015.pdf',
key: { e: 'AQAB', kty: 'RSA', n: '...' } },
uri: 'https://acme-v01.api.letsencrypt.org/acme/reg/71272',
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' }
*/
, writeFileAsync(path.join(accountDir, 'regr.json'),
JSON.stringify(regrBody),
'utf8')
]);
}).then(function () {
return {
id: accountId
, accountId: accountId
, email: args.email
, keypair: reg.keypair
, receipt: reg.receipt
};
});
}
// Accounts
, getAccountIdAsync: function (args) {
var pyconf = promisifyAll(require('pyconf'));
return pyconf.readFileAsync(args.renewalPath).then(function (renewal) {
var accountId = renewal.account;
renewal = renewal.account;
return accountId;
}, function (err) {
if ("ENOENT" === err.code) {
return store.accounts._getAccountIdByEmail(args);
}
return PromiseA.reject(err);
});
}
}
//
// Configs
//
, 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);
});
}
// Configs
, _checkHelperAsync: function (args) {
var pyconf = 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;
});
});
}
// Configs
, 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.domainKeyPath || args.keyPath || pyobj.keyPath;
return writeRenewalConfig(args);
});
}
// Configs
, allAsync: function (copy) {
copy.domains = [];
return 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;
};

View File

@ -0,0 +1,97 @@
{
"_args": [
[
"le-store-certbot@^2.1.0",
"/nodeapps/https-test/greenlock-express.js"
]
],
"_from": "le-store-certbot@>=2.1.0 <3.0.0",
"_hasShrinkwrap": false,
"_id": "le-store-certbot@2.2.1",
"_inCache": true,
"_installable": true,
"_location": "/le-store-certbot",
"_nodeVersion": "10.13.0",
"_npmOperationalInternal": {
"host": "s3://npm-registry-packages",
"tmp": "tmp/le-store-certbot_2.2.1_1541491178195_0.8624656290279973"
},
"_npmUser": {
"email": "coolaj86@gmail.com",
"name": "coolaj86"
},
"_npmVersion": "6.4.1",
"_phantomChildren": {},
"_requested": {
"name": "le-store-certbot",
"raw": "le-store-certbot@^2.1.0",
"rawSpec": "^2.1.0",
"scope": null,
"spec": ">=2.1.0 <3.0.0",
"type": "range"
},
"_requiredBy": [
"/",
"/greenlock"
],
"_resolved": "https://registry.npmjs.org/le-store-certbot/-/le-store-certbot-2.2.1.tgz",
"_shasum": "ee67d89991978855ca7cc8afa1812d2110abdc58",
"_shrinkwrap": null,
"_spec": "le-store-certbot@^2.1.0",
"_where": "/nodeapps/https-test/greenlock-express.js",
"author": {
"email": "coolaj86@gmail.com",
"name": "AJ ONeal",
"url": "https://coolaj86.com/"
},
"bugs": {
"url": "https://git.coolaj86.com/coolaj86/le-store-certbot.js/issues"
},
"dependencies": {
"mkdirp": "^0.5.1",
"pyconf": "^1.1.5",
"safe-replace": "^1.0.3"
},
"description": "The \"certbot\" storage strategy for Greenlock.js",
"devDependencies": {},
"directories": {},
"dist": {
"fileCount": 5,
"integrity": "sha512-BhljZjTULhbNBAT6RBiv4TeZegFraMxURYEvh3WRUI048zmXf4ZfC8gwbdu5fnD2tTCsS9fbsCOAQyrFBl4jlA==",
"npm-signature": "-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJb4UnqCRA9TVsSAnZWagAAiSkP/3lBxmMqtnmcqTV6BrRO\ntIeSn7JpBtQ9zdPRNhlze/N4hnUiT677i77fxEXcx3VGTW2qZdvzdgrMQBC/\nT/xxzYA8vqiBSwz94kCGe3dBAjtMm3EqEwteuV1kwyJSAr+rgNjYmnuwNJIL\ngNv0J8/xARH1LDAg+oe02u6frPID71IPDqH+WtvHgsMM4uj4HPsBLZRQKLBq\n32QW+5mbH/LDyqYhWNWWFmJqcXmLOCRtwPIeGbbXM7mCHzjtDBUO05kyzHXs\np07Vac1hpOeIPWsGufKsYY3UOd7pudr/iPhl7bcId6vJjWnGK+UmUQx3zZon\nijdm9haPg9hc3pOYyHV+SKO+1Kw6QHEihEENzWKU551kphlCI2yfI+r7I0vO\nw9IWKWoa5JjTpBoH0mYZ/E3MWNY1KaPZAyW0lKrQhTZ6LHt/8Od8Xx66GqB9\nxZWJNJoxyQMpIqp3AFNQQXdhYCLozBjA7gU4G0EEsXq11gNRoleMGA6vqLKf\n+E3SmDNMpHH0m8he92kBCh6T3BC3V0S3fluq77N4+HHf1vC1wh+k04IRoNNk\n0b6Czg91EdmZsOPtDMN0n5LvWa5WRiBZz0ChhX9BcEidlmzPqVNUY0C1EZYM\nxIiInpD9Bn91ZtH1rya+S21FB5alf5EdfGL6c60WGm3BFDX3D3NLKPrRxOgg\nWr37\r\n=MBXz\r\n-----END PGP SIGNATURE-----\r\n",
"shasum": "ee67d89991978855ca7cc8afa1812d2110abdc58",
"tarball": "https://registry.npmjs.org/le-store-certbot/-/le-store-certbot-2.2.1.tgz",
"unpackedSize": 28707
},
"gitHead": "bba58351e44f2f85a857de22472c6f43c94efbf2",
"homepage": "https://git.coolaj86.com/coolaj86/le-store-certbot.js",
"keywords": [
"certbot",
"le-store",
"le-store-",
"letsencrypt",
"node"
],
"license": "(MIT OR Apache-2.0)",
"main": "index.js",
"maintainers": [
{
"name": "coolaj86",
"email": "coolaj86@gmail.com"
}
],
"name": "le-store-certbot",
"optionalDependencies": {},
"readme": "ERROR: No README data found!",
"repository": {
"type": "git",
"url": "https://git.coolaj86.com/coolaj86/le-store-certbot.js"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"trulyOptionalDependencies": {
"bluebird": "^3.5.1"
},
"version": "2.2.1"
}

View File

@ -0,0 +1,83 @@
#cert = :configDir/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]
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
nginx_ctl = nginx
config_dir = :configDir
text_mode = True
# junk?
# https://github.com/letsencrypt/letsencrypt/issues/1955
func = <function obtain_cert at 0x7f093a163c08>
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_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 = False
[[webroot_map]]
# :hostname = :webroot_path