start transition to letsencrypt
This commit is contained in:
parent
738c249a3e
commit
5c7bf24c56
@ -28,11 +28,12 @@
|
|||||||
"homepage": "https://gitlab.com/pushrocks/cert#readme",
|
"homepage": "https://gitlab.com/pushrocks/cert#readme",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/minimatch": "2.x.x",
|
"@types/minimatch": "2.x.x",
|
||||||
"@types/q": "0.x.x",
|
"@types/q": "0.0.32",
|
||||||
"@types/shelljs": "0.x.x",
|
"@types/shelljs": "0.x.x",
|
||||||
"beautylog": "^6.0.0",
|
"beautylog": "^6.0.0",
|
||||||
"cflare": "0.0.10",
|
"cflare": "0.0.10",
|
||||||
"fs-extra": "^0.30.0",
|
"fs-extra": "^0.30.0",
|
||||||
|
"letsencrypt": "^2.1.8",
|
||||||
"lik": "^1.0.24",
|
"lik": "^1.0.24",
|
||||||
"q": "^1.4.1",
|
"q": "^1.4.1",
|
||||||
"shelljs": "^0.7.4",
|
"shelljs": "^0.7.4",
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import * as plugins from "./cert.plugins";
|
import * as q from 'q'
|
||||||
import * as paths from "./cert.paths";
|
import * as plugins from './cert.plugins'
|
||||||
import * as helpers from "./cert.classes.cert.helpers"
|
import * as paths from './cert.paths'
|
||||||
|
import * as helpers from './cert.classes.cert.helpers'
|
||||||
|
|
||||||
export interface ICertConstructorOptions {
|
export interface ICertConstructorOptions {
|
||||||
cfEmail: string,
|
cfEmail: string,
|
||||||
@ -8,27 +9,27 @@ export interface ICertConstructorOptions {
|
|||||||
sslDir?: string,
|
sslDir?: string,
|
||||||
gitOriginRepo?: string,
|
gitOriginRepo?: string,
|
||||||
testMode?: boolean
|
testMode?: boolean
|
||||||
};
|
}
|
||||||
|
|
||||||
export class Cert {
|
export class Cert {
|
||||||
private _cfEmail: string;
|
domainCertRequestMap: plugins.lik.Stringmap = new plugins.lik.Stringmap()
|
||||||
private _cfKey: string;
|
certificatesPresent: Certificate[]
|
||||||
private _sslDir: string;
|
certificatesValid: Certificate[]
|
||||||
private _gitOriginRepo: string;
|
private _cfEmail: string
|
||||||
private _testMode: boolean;
|
private _cfKey: string
|
||||||
domainCertRequestMap: plugins.lik.Stringmap = new plugins.lik.Stringmap();
|
private _sslDir: string
|
||||||
certificatesPresent: Certificate[];
|
private _gitOriginRepo: string
|
||||||
certificatesValid: Certificate[];
|
private _testMode: boolean
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for Cert object
|
* Constructor for Cert object
|
||||||
*/
|
*/
|
||||||
constructor(optionsArg: ICertConstructorOptions) {
|
constructor(optionsArg: ICertConstructorOptions) {
|
||||||
this._cfEmail = optionsArg.cfEmail;
|
this._cfEmail = optionsArg.cfEmail
|
||||||
this._cfKey = optionsArg.cfKey;
|
this._cfKey = optionsArg.cfKey
|
||||||
this._sslDir = optionsArg.sslDir;
|
this._sslDir = optionsArg.sslDir
|
||||||
this._gitOriginRepo = optionsArg.gitOriginRepo;
|
this._gitOriginRepo = optionsArg.gitOriginRepo
|
||||||
this._testMode = optionsArg.testMode;
|
this._testMode = optionsArg.testMode
|
||||||
// write hook config
|
// write hook config
|
||||||
let config = {
|
let config = {
|
||||||
cfEmail: this._cfEmail,
|
cfEmail: this._cfEmail,
|
||||||
@ -36,129 +37,111 @@ export class Cert {
|
|||||||
}
|
}
|
||||||
plugins.smartfile.memory.toFsSync(
|
plugins.smartfile.memory.toFsSync(
|
||||||
JSON.stringify(config),
|
JSON.stringify(config),
|
||||||
plugins.path.join(__dirname, "assets/config.json")
|
plugins.path.join(__dirname, 'assets/config.json')
|
||||||
);
|
)
|
||||||
// setup sslDir
|
// setup sslDir
|
||||||
if (!this._sslDir) this._sslDir = paths.defaultSslDir;
|
if (!this._sslDir) this._sslDir = paths.defaultSslDir
|
||||||
// setup Git
|
// setup Git
|
||||||
if (this._gitOriginRepo) {
|
if (this._gitOriginRepo) {
|
||||||
plugins.smartgit.init(this._sslDir);
|
plugins.smartgit.init(this._sslDir)
|
||||||
plugins.smartgit.remote.add(this._sslDir, "origin", this._gitOriginRepo);
|
plugins.smartgit.remote.add(this._sslDir, 'origin', this._gitOriginRepo)
|
||||||
this.sslGitOriginPull();
|
this.sslGitOriginPull()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// setup leSh config;
|
|
||||||
let leShConfigString;
|
|
||||||
if (this._testMode) {
|
|
||||||
leShConfigString = `CA="https://acme-staging.api.letsencrypt.org/directory"\n`;
|
|
||||||
} else {
|
|
||||||
leShConfigString = " ";
|
|
||||||
};
|
|
||||||
plugins.smartfile.memory.toFsSync(
|
|
||||||
leShConfigString,
|
|
||||||
paths.leShConfig
|
|
||||||
);
|
|
||||||
plugins.shelljs.exec("chmod 700 " + paths.letsencryptSh);
|
|
||||||
plugins.shelljs.exec("chmod 700 " + paths.certHook);
|
|
||||||
plugins.shelljs.exec(
|
|
||||||
`bash -c "${paths.letsencryptSh} -c --no-lock -f ${paths.leShConfig} -d notthere.notthere -t dns-01 -k ${paths.certHook} -o ${paths.certDir}"`,
|
|
||||||
{
|
|
||||||
silent: true
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pulls already requested certificates from git origin
|
* Pulls already requested certificates from git origin
|
||||||
*/
|
*/
|
||||||
sslGitOriginPull = () => {
|
sslGitOriginPull = () => {
|
||||||
if (this._gitOriginRepo) {
|
if (this._gitOriginRepo) {
|
||||||
plugins.smartgit.pull(this._sslDir, "origin", "master");
|
plugins.smartgit.pull(this._sslDir, 'origin', 'master')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pushes all new requested certificates to git origin
|
* Pushes all new requested certificates to git origin
|
||||||
*/
|
*/
|
||||||
sslGitOriginAddCommitPush = () => {
|
sslGitOriginAddCommitPush = () => {
|
||||||
if (this._gitOriginRepo) {
|
if (this._gitOriginRepo) {
|
||||||
plugins.smartgit.add.addAll(this._sslDir);
|
plugins.smartgit.add.addAll(this._sslDir)
|
||||||
plugins.smartgit.commit(this._sslDir, "added new SSL certificates and deleted obsolete ones.");
|
plugins.smartgit.commit(this._sslDir, 'added new SSL certificates and deleted obsolete ones.')
|
||||||
plugins.smartgit.push(this._sslDir, "origin", "master");
|
plugins.smartgit.push(this._sslDir, 'origin', 'master')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gets a ssl cert for a given domain
|
* gets a ssl cert for a given domain
|
||||||
*/
|
*/
|
||||||
getDomainCert(domainNameArg: string, optionsArg: { force: boolean } = { force: false }) {
|
getDomainCert(domainNameArg: string, optionsArg: { force: boolean } = { force: false }) {
|
||||||
let done = plugins.q.defer();
|
let done = q.defer()
|
||||||
let domainStringData = new plugins.smartstring.Domain(domainNameArg);
|
let domainStringData = new plugins.smartstring.Domain(domainNameArg)
|
||||||
let sameZoneRequesting: boolean = this.domainCertRequestMap.checkMinimatch("*" + domainStringData.zoneName)
|
let sameZoneRequesting: boolean = this.domainCertRequestMap.checkMinimatch('*' + domainStringData.zoneName)
|
||||||
// make sure no one else requires the same domain at the same time
|
// make sure no one else requires the same domain at the same time
|
||||||
if (!this.domainCertRequestMap.checkString(domainNameArg)) {
|
if (!this.domainCertRequestMap.checkString(domainNameArg)) {
|
||||||
this.domainCertRequestMap.addString(domainNameArg);
|
this.domainCertRequestMap.addString(domainNameArg)
|
||||||
if (!helpers.checkDomainsStillValid(domainNameArg, this._sslDir) || optionsArg.force) {
|
if (!helpers.checkDomainsStillValid(domainNameArg, this._sslDir) || optionsArg.force) {
|
||||||
if (!sameZoneRequesting) {
|
if (!sameZoneRequesting) {
|
||||||
this.sslGitOriginPull();
|
this.sslGitOriginPull()
|
||||||
plugins.smartfile.fs.ensureDir(paths.certDir);
|
plugins.smartfile.fs.ensureDir(paths.certDir)
|
||||||
plugins.beautylog.info(`getting cert for ${domainNameArg}`);
|
plugins.beautylog.info(`getting cert for ${domainNameArg}`)
|
||||||
plugins.shelljs.exec(
|
plugins.shelljs.exec(
|
||||||
`bash -c "${paths.letsencryptSh} -c --no-lock -f ${paths.leShConfig} -d ${domainNameArg} -t dns-01 -k ${paths.certHook} -o ${paths.certDir}"`,
|
`bash -c "${paths.letsencryptSh} -c --no-lock -f ${paths.leShConfig} -d ${domainNameArg} -t dns-01 -k ${paths.certHook} -o ${paths.certDir}"`,
|
||||||
{
|
{
|
||||||
silent: true
|
silent: true
|
||||||
},
|
},
|
||||||
(codeArg, stdoutArg) => {
|
(codeArg, stdoutArg) => {
|
||||||
if (codeArg == 0) {
|
if (codeArg === 0) {
|
||||||
console.log(stdoutArg);
|
console.log(stdoutArg)
|
||||||
let fetchedCertsArray: string[] = plugins.smartfile.fs.listFoldersSync(paths.certDir);
|
let fetchedCertsArray: string[] = plugins.smartfile.fs.listFoldersSync(paths.certDir)
|
||||||
if (fetchedCertsArray.indexOf(domainNameArg) != -1) {
|
if (fetchedCertsArray.indexOf(domainNameArg) != -1) {
|
||||||
helpers.updateSslDirSync(this._sslDir, domainNameArg);
|
helpers.updateSslDirSync(this._sslDir, domainNameArg)
|
||||||
plugins.smartfile.fs.removeSync(plugins.path.join(paths.certDir, domainNameArg));
|
plugins.smartfile.fs.removeSync(plugins.path.join(paths.certDir, domainNameArg))
|
||||||
this.sslGitOriginAddCommitPush();
|
this.sslGitOriginAddCommitPush()
|
||||||
} else {
|
} else {
|
||||||
plugins.beautylog.error(`Couldn't copy final certificate for ${domainNameArg}!`);
|
plugins.beautylog.error(`Couldn't copy final certificate for ${domainNameArg}!`)
|
||||||
};
|
|
||||||
done.resolve();
|
|
||||||
} else {
|
|
||||||
plugins.beautylog.warn(`${domainNameArg} scheduled for retry. Waiting 1 minute!`);
|
|
||||||
helpers.scheduleRetry(domainNameArg, this).then(done.resolve);
|
|
||||||
}
|
}
|
||||||
this.domainCertRequestMap.removeString(domainNameArg);
|
done.resolve()
|
||||||
}
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
plugins.beautylog.info(`${domainNameArg} is waiting for domains names of same zone to finish`);
|
plugins.beautylog.warn(`${domainNameArg} scheduled for retry. Waiting 1 minute!`)
|
||||||
this.domainCertRequestMap.removeString(domainNameArg);
|
helpers.scheduleRetry(domainNameArg, this).then(done.resolve)
|
||||||
|
}
|
||||||
|
this.domainCertRequestMap.removeString(domainNameArg)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
plugins.beautylog.info(`${domainNameArg} is waiting for domains names of same zone to finish`)
|
||||||
|
this.domainCertRequestMap.removeString(domainNameArg)
|
||||||
this.domainCertRequestMap.registerUntilTrue(
|
this.domainCertRequestMap.registerUntilTrue(
|
||||||
() => {
|
() => {
|
||||||
return !this.domainCertRequestMap.checkMinimatch("*" + domainStringData.zoneName);
|
return !this.domainCertRequestMap.checkMinimatch('*' + domainStringData.zoneName)
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
this.getDomainCert(domainNameArg).then(done.resolve);
|
this.getDomainCert(domainNameArg).then(done.resolve)
|
||||||
}
|
}
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
plugins.beautylog.info("certificate for " + domainNameArg + " is still valid! Not fetching new one!");
|
plugins.beautylog.info('certificate for ' + domainNameArg + ' is still valid! Not fetching new one!')
|
||||||
this.domainCertRequestMap.removeString(domainNameArg);
|
this.domainCertRequestMap.removeString(domainNameArg)
|
||||||
done.resolve();
|
done.resolve()
|
||||||
};
|
}
|
||||||
} else {
|
} else {
|
||||||
plugins.beautylog.warn(`${domainNameArg} is already requesting`);
|
plugins.beautylog.warn(`${domainNameArg} is already requesting`)
|
||||||
};
|
}
|
||||||
|
|
||||||
return done.promise;
|
return done.promise
|
||||||
};
|
}
|
||||||
cleanOldCertificates() {
|
cleanOldCertificates() {
|
||||||
|
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Certificate {
|
export class Certificate {
|
||||||
domainName: string;
|
domainName: string
|
||||||
creationDate: Date;
|
creationDate: Date
|
||||||
expiryDate: Date;
|
expiryDate: Date
|
||||||
constructor() {
|
constructor() {
|
||||||
|
|
||||||
};
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,3 @@
|
|||||||
#!/usr/bin/env node
|
|
||||||
// the shebang line above makes sure this script will get interpreted by node
|
|
||||||
|
|
||||||
import * as plugins from "./cert.plugins";
|
import * as plugins from "./cert.plugins";
|
||||||
import * as paths from "./cert.paths";
|
import * as paths from "./cert.paths";
|
||||||
|
|
||||||
|
@ -1,13 +1,28 @@
|
|||||||
import "typings-global";
|
import 'typings-global'
|
||||||
export import beautylog = require("beautylog");
|
import * as beautylog from 'beautylog'
|
||||||
export import cflare = require("cflare");
|
import * as cflare from 'cflare'
|
||||||
export let fs = require("fs-extra");
|
let fs = require('fs-extra')
|
||||||
export import lik = require("lik");
|
let letsencrypt = require('letsencrypt')
|
||||||
export import path = require("path");
|
import * as lik from 'lik'
|
||||||
export import q = require("q");
|
import * as path from 'path'
|
||||||
export import shelljs = require("shelljs");
|
import * as q from 'q'
|
||||||
export import smartcli = require("smartcli");
|
import * as shelljs from 'shelljs'
|
||||||
export import smartfile = require("smartfile");
|
import * as smartcli from 'smartcli'
|
||||||
export import smartgit = require("smartgit");
|
import * as smartfile from 'smartfile'
|
||||||
export import smartstring = require("smartstring");
|
import * as smartgit from 'smartgit'
|
||||||
|
import * as smartstring from 'smartstring'
|
||||||
|
|
||||||
|
export {
|
||||||
|
beautylog,
|
||||||
|
cflare,
|
||||||
|
fs,
|
||||||
|
letsencrypt,
|
||||||
|
lik,
|
||||||
|
path,
|
||||||
|
q,
|
||||||
|
shelljs,
|
||||||
|
smartcli,
|
||||||
|
smartfile,
|
||||||
|
smartgit,
|
||||||
|
smartstring
|
||||||
|
}
|
||||||
|
@ -1,23 +0,0 @@
|
|||||||
import * as plugins from "./cert.plugins";
|
|
||||||
import * as paths from "./cert.paths";
|
|
||||||
|
|
||||||
export let startInstall = () => {
|
|
||||||
let done = plugins.q.defer();
|
|
||||||
plugins.beautylog.info("installing letsencrypt.sh locally...");
|
|
||||||
|
|
||||||
plugins.fs.ensureDir(plugins.path.join(__dirname, "assets/"));
|
|
||||||
plugins.smartfile.remote.toFs(
|
|
||||||
"https://raw.githubusercontent.com/lukas2511/letsencrypt.sh/master/letsencrypt.sh",
|
|
||||||
paths.letsencryptSh
|
|
||||||
).then(() => {
|
|
||||||
plugins.beautylog.success("Done!");
|
|
||||||
done.resolve();
|
|
||||||
});
|
|
||||||
return done.promise;
|
|
||||||
};
|
|
||||||
|
|
||||||
let smartcli = new plugins.smartcli.Smartcli();
|
|
||||||
smartcli.addCommand({
|
|
||||||
commandName:"install"
|
|
||||||
}).then(startInstall);
|
|
||||||
smartcli.startParse();
|
|
3
tslint.json
Normal file
3
tslint.json
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"extends": "tslint-config-standard"
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user