Compare commits

..

3 Commits

Author SHA1 Message Date
bc9a3d179d move manager.js to own module 2019-10-21 17:37:51 -06:00
0da6448f5d export PKG_DIR for other libs to override 2019-10-21 17:37:31 -06:00
a865cc9f52 fix deps and urls 2019-10-21 17:16:32 -06:00
3 changed files with 13 additions and 271 deletions

View File

@ -18,11 +18,11 @@
}, },
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://git.coolaj86.com/coolaj86/bluecrypt-acme.js.git" "url": "https://git.rootprojects.org/root/greenlock.js.git"
}, },
"keywords": [ "keywords": [
"ACME",
"Let's Encrypt", "Let's Encrypt",
"ACME",
"browser", "browser",
"EC", "EC",
"RSA", "RSA",
@ -39,7 +39,6 @@
"@root/keypairs": "^0.9.0", "@root/keypairs": "^0.9.0",
"@root/mkdirp": "^1.0.0", "@root/mkdirp": "^1.0.0",
"@root/request": "^1.3.10", "@root/request": "^1.3.10",
"acme-dns-01-digitalocean": "^3.0.1",
"acme-http-01-standalone": "^3.0.0", "acme-http-01-standalone": "^3.0.0",
"cert-info": "^1.5.1", "cert-info": "^1.5.1",
"greenlock-store-fs": "^3.0.2", "greenlock-store-fs": "^3.0.2",

View File

@ -4,7 +4,9 @@ var P = module.exports;
var spawn = require('child_process').spawn; var spawn = require('child_process').spawn;
var spawnSync = require('child_process').spawnSync; var spawnSync = require('child_process').spawnSync;
var PKG_DIR = __dirname;
// Exported for CLIs and such to override
P.PKG_DIR = __dirname;
P._load = function(modname) { P._load = function(modname) {
try { try {
@ -35,7 +37,7 @@ P._installSync = function(moduleName) {
try { try {
cmd = spawnSync(npm, args, { cmd = spawnSync(npm, args, {
cwd: PKG_DIR, cwd: P.PKG_DIR,
windowsHide: true windowsHide: true
}); });
} catch (e) { } catch (e) {
@ -45,7 +47,7 @@ P._installSync = function(moduleName) {
' ' + ' ' +
args.join(' ') + args.join(' ') +
"' in '" + "' in '" +
PKG_DIR + P.PKG_DIR +
"'" "'"
); );
console.error(e.message); console.error(e.message);
@ -71,12 +73,12 @@ P._installSync = function(moduleName) {
' ' + ' ' +
args.join(' ') + args.join(' ') +
"' in '" + "' in '" +
PKG_DIR + P.PKG_DIR +
"'" "'"
); );
console.error( console.error(
'Try for yourself:\n\tcd ' + PKG_DIR + '\n\tnpm ' + args.join(' ') 'Try for yourself:\n\tcd ' + P.PKG_DIR + '\n\tnpm ' + args.join(' ')
); );
process.exit(1); process.exit(1);
@ -92,7 +94,7 @@ P._install = function(moduleName) {
var args = ['install', '--save', moduleName]; var args = ['install', '--save', moduleName];
var out = ''; var out = '';
var cmd = spawn(npm, args, { var cmd = spawn(npm, args, {
cwd: PKG_DIR, cwd: P.PKG_DIR,
windowsHide: true windowsHide: true
}); });
@ -110,7 +112,7 @@ P._install = function(moduleName) {
' ' + ' ' +
args.join(' ') + args.join(' ') +
"' in '" + "' in '" +
PKG_DIR + P.PKG_DIR +
"'" "'"
); );
console.error(e.message); console.error(e.message);
@ -134,12 +136,12 @@ P._install = function(moduleName) {
' ' + ' ' +
args.join(' ') + args.join(' ') +
"' in '" + "' in '" +
PKG_DIR + P.PKG_DIR +
"'" "'"
); );
console.error( console.error(
'Try for yourself:\n\tcd ' + 'Try for yourself:\n\tcd ' +
PKG_DIR + P.PKG_DIR +
'\n\tnpm ' + '\n\tnpm ' +
args.join(' ') args.join(' ')
); );

View File

@ -1,259 +0,0 @@
'use strict';
var Manage = module.exports;
var sfs = require('safe-replace').create({ tmp: 'tmp', bak: 'bak' });
var promisify = require('util').promisify;
var fs = require('fs');
var readFile = promisify(fs.readFile);
var statFile = promisify(fs.stat);
var homedir = require('os').homedir();
var path = require('path');
var mkdirp = promisify(require('@root/mkdirp'));
Manage.create = function(opts) {
if (!opts) {
opts = {};
}
if (!opts.configFile) {
opts.configFile = '~/.config/greenlock/config.json';
}
opts.configFile = opts.configFile.replace('~/', homedir + '/');
var manage = {};
manage.ping = function() {
return Manage._ping(manage, opts);
};
manage._txPromise = new Promise(function(resolve) {
resolve();
});
manage._lastStat = {
size: 0,
mtimeMs: 0
};
manage._config = {};
manage._save = function(config) {
return mkdirp(path.dirname(opts.configFile)).then(function() {
return sfs
.writeFileAsync(opts.configFile, JSON.stringify(config), 'utf8')
.then(function() {
return statFile(opts.configFile).then(function(stat) {
manage._lastStat.size = stat.size;
manage._lastStat.mtimeMs = stat.mtimeMs;
});
});
});
};
manage.add = function(args) {
manage._txPromise = manage._txPromise.then(function() {
// if the fs has changed since we last wrote, get the lastest from disk
return Manage._getLatest(manage, opts).then(function(config) {
// TODO move to Greenlock.add
var subject = args.subject || args.domain;
var primary = subject;
var altnames = args.altnames || args.domains;
if ('string' !== typeof primary) {
if (!Array.isArray(altnames) || !altnames.length) {
throw new Error('there needs to be a subject');
}
primary = altnames.slice(0).sort()[0];
}
if (!Array.isArray(altnames) || !altnames.length) {
altnames = [primary];
}
primary = primary.toLowerCase();
altnames = altnames.map(function(name) {
return name.toLowerCase();
});
if (!config.sites) {
config.sites = {};
}
var site = config.sites[primary];
if (!site) {
site = config.sites[primary] = { altnames: [] };
}
// The goal is to make this decently easy to manage by hand without mistakes
// but also reasonably easy to error check and correct
// and to make deterministic auto-corrections
// TODO added, removed, moved (duplicate), changed
site.subscriberEmail = site.subscriberEmail;
site.subject = subject;
site.altnames = altnames;
site.issuedAt = site.issuedAt || 0;
site.expiresAt = site.expiresAt || 0;
site.lastAttemptAt = site.lastAttemptAt || 0;
// re-add if this was deleted
site.deletedAt = 0;
if (
site.altnames
.slice(0)
.sort()
.join() !==
altnames
.slice(0)
.sort()
.join()
) {
site.expiresAt = 0;
site.issuedAt = 0;
}
// These should usually be empty, for most situations
site.subscriberEmail = args.subscriberEmail;
site.customerEmail = args.customerEmail;
site.challenges = args.challenges;
site.store = args.store;
console.log('[debug] save site', site);
return manage._save(config).then(function() {
return JSON.parse(JSON.stringify(site));
});
});
});
return manage._txPromise;
};
manage.find = function(args) {
return Manage._getLatest(manage, opts).then(function(config) {
// i.e. find certs more than 30 days old
//args.issuedBefore = Date.now() - 30 * 24 * 60 * 60 * 1000;
// i.e. find certs more that will expire in less than 45 days
//args.expiresBefore = Date.now() + 45 * 24 * 60 * 60 * 1000;
var issuedBefore = args.issuedBefore || 0;
var expiresBefore =
args.expiresBefore || Date.now() + 21 * 24 * 60 * 60 * 1000;
// TODO match ANY domain on any cert
var sites = Object.keys(config.sites)
.filter(function(sub) {
var site = config.sites[sub];
if (
!site.deletedAt ||
site.expiresAt < expiresBefore ||
site.issuedAt < issuedBefore
) {
if (!args.subject || sub === args.subject) {
return true;
}
}
})
.map(function(name) {
var site = config.sites[name];
console.debug('debug', site);
return {
subject: site.subject,
altnames: site.altnames,
issuedAt: site.issuedAt,
expiresAt: site.expiresAt,
renewOffset: site.renewOffset,
renewStagger: site.renewStagger,
renewAt: site.renewAt,
subscriberEmail: site.subscriberEmail,
customerEmail: site.customerEmail,
challenges: site.challenges,
store: site.store
};
});
return sites;
});
};
manage.remove = function(args) {
if (!args.subject) {
throw new Error('should have a subject for sites to remove');
}
manage._txPromise = manage.txPromise.then(function() {
return Manage._getLatest(manage, opts).then(function(config) {
var site = config.sites[args.subject];
if (!site) {
return {};
}
site.deletedAt = Date.now();
return JSON.parse(JSON.stringify(site));
});
});
return manage._txPromise;
};
manage.notifications = function(args) {
// TODO define message types
console.info(args.event, args.message);
};
manage.errors = function(err) {
// err.subject
// err.altnames
// err.challenge
// err.challengeOptions
// err.store
// err.storeOptions
console.error('Failure with ', err.subject);
};
manage.update = function(args) {
manage._txPromise = manage.txPromise.then(function() {
return Manage._getLatest(manage, opts).then(function(config) {
var site = config.sites[args.subject];
site.issuedAt = args.issuedAt;
site.expiresAt = args.expiresAt;
site.renewAt = args.renewAt;
// foo
});
});
return manage._txPromise;
};
return manage;
};
Manage._getLatest = function(mng, opts) {
return statFile(opts.configFile)
.catch(function(err) {
if ('ENOENT' === err.code) {
return {
size: 0,
mtimeMs: 0
};
}
err.context = 'manager_read';
throw err;
})
.then(function(stat) {
if (
stat.size === mng._lastStat.size &&
stat.mtimeMs === mng._lastStat.mtimeMs
) {
return mng._config;
}
return readFile(opts.configFile, 'utf8').then(function(data) {
mng._lastStat = stat;
mng._config = JSON.parse(data);
return mng._config;
});
});
};
Manage._ping = function(mng, opts) {
if (mng._pingPromise) {
return mng._pingPromise;
}
mng._pringPromise = Promise.resolve().then(function() {
// TODO file permissions
if (!opts.configFile) {
throw new Error('no config file location provided');
}
JSON.parse(fs.readFileSync(opts.configFile, 'utf8'));
});
return mng._pingPromise;
};