55 Commits

Author SHA1 Message Date
6c67556756 1.0.3 2016-07-22 03:39:54 +02:00
8e892c14bc test 2016-07-22 03:39:45 +02:00
adcf49d729 1.0.2 2016-07-22 03:28:33 +02:00
22d79491ce testing 2016-07-22 03:28:30 +02:00
1b23d1e435 1.0.1 2016-07-22 02:59:33 +02:00
1c2063ef82 now retrying 2016-07-22 02:59:11 +02:00
d48a6c8315 1.0.0 2016-07-22 02:13:23 +02:00
1185480b91 0.0.18 2016-07-22 02:12:58 +02:00
afddfe5217 improve README 2016-07-22 02:12:49 +02:00
159ffe0728 now requesting in parallel 2016-07-22 02:11:04 +02:00
3c3da30966 update README 2016-07-21 15:02:51 +02:00
d4b249a59b update 2016-07-21 14:58:05 +02:00
06256f7a4d 0.0.17 2016-07-13 16:06:27 +02:00
be6fc3adfd cleanup after oneself 2016-07-13 16:06:16 +02:00
5ccf5b81e2 0.0.16 2016-07-13 12:09:41 +02:00
d06a2cee2f update sslDir handling 2016-07-13 12:09:34 +02:00
a7525184ef 0.0.15 2016-07-12 18:00:15 +02:00
ae9865749a use interface for Cert constructor 2016-07-12 18:00:08 +02:00
b2482b3cfd 0.0.14 2016-07-12 16:36:34 +02:00
41988da3ed fix types 2016-07-12 16:36:29 +02:00
55d450be69 0.0.13 2016-07-06 03:23:54 +02:00
ae2ade8680 updated test 2016-07-06 03:23:51 +02:00
d7ec7e254e 0.0.12 2016-07-06 03:10:49 +02:00
4bd7aee8ea add typings to package.json 2016-07-06 03:10:36 +02:00
bf711c2bb6 update tests 2016-07-04 21:57:14 +02:00
eb9e6679c4 0.0.11 2016-07-04 09:00:31 +02:00
96c801cdbd now fully working 2016-07-04 08:41:58 +02:00
ee844fd348 implement Git Repo Sync 2016-07-04 04:56:49 +02:00
d06c7059bb update dependency typings 2016-07-01 06:26:10 +02:00
d36f2f0c33 update for latest npmts compatibility 2016-07-01 06:18:48 +02:00
4bcf925b28 0.0.10 2016-06-29 22:55:50 +02:00
484e75ac34 nwo creating configfile per certificate all right 2016-06-28 10:34:59 +02:00
ad792f32dd now has sslDir implemented 2016-06-28 09:32:01 +02:00
05b7c7ab45 improve logs and cooldown 2016-06-28 05:53:49 +02:00
d94a097443 start Certificate class logic 2016-06-23 04:37:18 +02:00
645e46dc01 start implementing validity check 2016-06-23 03:46:37 +02:00
5c87851ab8 remove some unused deps 2016-06-22 14:58:46 +02:00
0fd3bd262b start implementation of sslDir and gitOrigin 2016-06-22 13:55:38 +02:00
732e35d295 compile 2016-06-22 13:35:15 +02:00
e9135c42af 0.0.9 2016-06-22 13:22:21 +02:00
a850243c59 now working 2016-06-22 13:22:09 +02:00
8dc75feb8d update structure 2016-06-21 21:08:04 +02:00
ac7160c3a3 add should devDeps 2016-06-21 20:04:44 +02:00
1cdcd332d4 install step now working 2016-06-21 20:02:57 +02:00
5e10df8e5a update REAMDE 2016-06-18 16:14:57 +02:00
e67677d57d 0.0.6 2016-06-18 16:03:58 +02:00
d5b5e8d612 update Readme 2016-06-18 16:03:46 +02:00
bbee7923e4 more structure 2016-06-18 15:59:03 +02:00
04be5f88eb 0.0.5 2016-06-18 15:42:53 +02:00
3c626908f1 compile 2016-06-18 15:42:49 +02:00
821b2f95b0 fix repo link 2016-06-18 15:42:09 +02:00
c0753c185f 0.0.4 2016-06-18 15:13:06 +02:00
dad659e2ed fix description 2016-06-18 15:13:02 +02:00
d1f1ae271a 0.0.3 2016-06-18 15:09:48 +02:00
7bd18cb927 fix branches for ci 2016-06-18 15:09:44 +02:00
28 changed files with 889 additions and 40 deletions

5
.gitignore vendored
View File

@ -1,3 +1,6 @@
node_modules node_modules
docs/ docs/
coverage/ coverage/
.nogit/
dist/assets/
test/assets/

View File

@ -1,35 +1,26 @@
image: hosttoday/ht-docker-node:npmts image: hosttoday/ht-docker-node:npmts
stages: stages:
- test - test1
- test2
- release - release
testLEGACY:
stage: test
script:
- npmci test legacy
only:
- master
tags:
- docker
- lossless
testLTS: testLTS:
stage: test stage: test1
script: script:
- npmci test lts - npmci test lts
only: only:
- master - tags
tags: tags:
- docker - docker
- lossless - lossless
testSTABLE: testSTABLE:
stage: test stage: test2
script: script:
- npmci test stable - npmci test stable
only: only:
- master - tags
tags: tags:
- docker - docker
- lossless - lossless
@ -39,6 +30,6 @@ release:
script: script:
- npmci publish npm - npmci publish npm
only: only:
- master - tags
tags: tags:
- lossless - lossless

View File

@ -1,16 +1,39 @@
# Cert # Cert
Easily obain SSL certificates from LetsEncrypt. Supports DNS-01 challenge. TypeScript ready. Easily obain SSL certificates from LetsEncrypt. Supports DNS-01 challenge. TypeScript ready.
## Status
[![build status](https://gitlab.com/pushrocks/cert/badges/master/build.svg)](https://gitlab.com/pushrocks/cert/commits/master)
## Usage ## Usage
```typescript ```typescript
import {Cert} from "cert"; import {Cert} from "cert";
myCert = new Cert({ let myCert = new Cert({
cfEmail = "some@cloudflare.email", cfEmail: "some@cloudflare.email",
cfKey = "someCloudflareApiKey", cfKey: "someCloudflareApiKey",
outputPath = "someOutputPath" // NOTE: if you already have certificates, make sure you put them in here, so cert only requires the missing ones sslDir: "someOutputPath", // NOTE: if you already have certificates, make sure you put them in here, so cert only requires the missing ones
gitOriginRepo: "git@githhub.com/someuser/somereopo" // good for persistence in highly volatile environments like docker
}); });
myCert.getDomainCert("example.com"); myCert.getDomainCert("example.com"); // returns promise
``` ```
> **Note:** cert supports async parallel cert fetching. If called twice for the same domain, only the first one will trigger.
## sslDir
to use the certificates it is important to understand what the structure of the ssl directory looks like.
## using a git origin repo.
Often times you want to keep track of certificates in order to keep them
even if the point of initial certificate request is gone. Imagine you have a dockerenvironement
and you keep starting new container versions for the same domain. YOu ideally want to use a proxy
that handles SSL managemet for you. But even the proxy needs to be updated from time to time.
So you need some kind of persistence between versions. This is why you can sync up all certificates to a git repo over ssh
Just make sure your id_rsa is in place for the node user and is allowed for the origin repo.
## Environment
Since cert relies on [letsencrypt.sh](https://github.com/lukas2511/letsencrypt.sh) in the background bash is needed on the system.
If you plan on using this on Windows check out [npmdocker](https://www.npmjs.com/package/npmdocker) which runs node programs in docker.
As of summer 2016 Windows will also ship with bash nativly included.

5
dist/cert.helpers.d.ts vendored Normal file
View File

@ -0,0 +1,5 @@
/// <reference types="q" />
import { Cert } from "./index.ts";
import * as plugins from "./cert.plugins";
export declare let accountsKeyPresent: () => plugins.q.Promise<{}>;
export declare let scheduleRetry: (domainArg: string, certClassArg: Cert) => plugins.q.Promise<{}>;

25
dist/cert.helpers.js vendored Normal file
View File

@ -0,0 +1,25 @@
"use strict";
const plugins = require("./cert.plugins");
let firstCall = true;
let enoughTime = false;
exports.accountsKeyPresent = () => {
let done = plugins.q.defer();
if (firstCall) {
done.resolve();
firstCall = false;
}
else {
setTimeout(done.resolve, 5000);
}
;
return done.promise;
};
exports.scheduleRetry = (domainArg, certClassArg) => {
let done = plugins.q.defer();
setTimeout(() => {
certClassArg.getDomainCert(domainArg)
.then(done.resolve);
}, 20000);
return done.promise;
};
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2VydC5oZWxwZXJzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvY2VydC5oZWxwZXJzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFDQSxNQUFZLE9BQU8sV0FBTSxnQkFBZ0IsQ0FBQyxDQUFBO0FBRzFDLElBQUksU0FBUyxHQUFHLElBQUksQ0FBQztBQUNyQixJQUFJLFVBQVUsR0FBRyxLQUFLLENBQUM7QUFDWiwwQkFBa0IsR0FBRztJQUM1QixJQUFJLElBQUksR0FBRyxPQUFPLENBQUMsQ0FBQyxDQUFDLEtBQUssRUFBRSxDQUFDO0lBQzdCLEVBQUUsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUM7UUFDWixJQUFJLENBQUMsT0FBTyxFQUFFLENBQUM7UUFDZixTQUFTLEdBQUcsS0FBSyxDQUFDO0lBQ3RCLENBQUM7SUFBRSxJQUFJLENBQUMsQ0FBQztRQUNMLFVBQVUsQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFDLElBQUksQ0FBQyxDQUFDO0lBQ2xDLENBQUM7SUFBQSxDQUFDO0lBQ0YsTUFBTSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUM7QUFDeEIsQ0FBQyxDQUFDO0FBRVMscUJBQWEsR0FBRyxDQUFDLFNBQWdCLEVBQUMsWUFBaUI7SUFDMUQsSUFBSSxJQUFJLEdBQUcsT0FBTyxDQUFDLENBQUMsQ0FBQyxLQUFLLEVBQUUsQ0FBQztJQUM3QixVQUFVLENBQUM7UUFDUCxZQUFZLENBQUMsYUFBYSxDQUFDLFNBQVMsQ0FBQzthQUNoQyxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQzVCLENBQUMsRUFBQyxLQUFLLENBQUMsQ0FBQztJQUNULE1BQU0sQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDO0FBQ3hCLENBQUMsQ0FBQyJ9

65
dist/cert.hook.js vendored Executable file
View File

@ -0,0 +1,65 @@
#!/usr/bin/env node
"use strict";
const plugins = require("./cert.plugins");
const paths = require("./cert.paths");
let smartcli = new plugins.smartcli.Smartcli();
let config = plugins.smartfile.fs.toObjectSync(paths.config);
let cflare = new plugins.cflare.CflareAccount();
cflare.auth({
email: config.cfEmail,
key: config.cfKey
});
let setChallenge = (domainNameArg, challengeArg) => {
let done = plugins.q.defer();
plugins.beautylog.log("setting challenge for " + domainNameArg);
cflare.createRecord(prefixName(domainNameArg), "TXT", challengeArg).then(() => {
plugins.beautylog.ok("Challenge has been set!");
plugins.beautylog.info("We need to cool down to let DNS propagate to edge locations!");
cooldown().then(() => {
done.resolve();
});
});
return done.promise;
};
let cleanChallenge = (domainNameArg) => {
let done = plugins.q.defer();
plugins.beautylog.log("cleaning challenge for " + domainNameArg);
cflare.removeRecord(prefixName(domainNameArg), "TXT");
return done.promise;
};
let cooldown = () => {
let done = plugins.q.defer();
let cooldowntime = 120000;
let passedTime = 0;
plugins.beautylog.log("Cooling down! " + (cooldowntime / 1000).toString() + " seconds left");
let coolDownCounter = () => {
setTimeout(() => {
if (cooldowntime <= passedTime) {
plugins.beautylog.ok("Cooled down!");
done.resolve();
}
else {
passedTime = passedTime + 5000;
plugins.beautylog.log("Cooling down! " + ((cooldowntime - passedTime) / 1000).toString() + " seconds left");
coolDownCounter();
}
}, 5000);
};
coolDownCounter();
return done.promise;
};
let prefixName = (domainNameArg) => {
return "_acme-challenge." + domainNameArg;
};
smartcli.addCommand({
commandName: "deploy_challenge"
}).then((argv) => {
setChallenge(argv._[1], argv._[3]);
});
smartcli.addCommand({
commandName: "clean_challenge"
}).then((argv) => {
cleanChallenge(argv._[1]);
});
smartcli.startParse();
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2VydC5ob29rLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvY2VydC5ob29rLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBR0EsTUFBWSxPQUFPLFdBQU0sZ0JBQWdCLENBQUMsQ0FBQTtBQUMxQyxNQUFZLEtBQUssV0FBTSxjQUFjLENBQUMsQ0FBQTtBQUV0QyxJQUFJLFFBQVEsR0FBRyxJQUFJLE9BQU8sQ0FBQyxRQUFRLENBQUMsUUFBUSxFQUFFLENBQUM7QUFFL0MsSUFBSSxNQUFNLEdBQUcsT0FBTyxDQUFDLFNBQVMsQ0FBQyxFQUFFLENBQUMsWUFBWSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQztBQUM3RCxJQUFJLE1BQU0sR0FBRyxJQUFJLE9BQU8sQ0FBQyxNQUFNLENBQUMsYUFBYSxFQUFFLENBQUM7QUFDaEQsTUFBTSxDQUFDLElBQUksQ0FBQztJQUNSLEtBQUssRUFBRSxNQUFNLENBQUMsT0FBTztJQUNyQixHQUFHLEVBQUUsTUFBTSxDQUFDLEtBQUs7Q0FDcEIsQ0FBQyxDQUFDO0FBRUgsSUFBSSxZQUFZLEdBQUcsQ0FBQyxhQUFxQixFQUFFLFlBQW9CO0lBQzNELElBQUksSUFBSSxHQUFHLE9BQU8sQ0FBQyxDQUFDLENBQUMsS0FBSyxFQUFFLENBQUM7SUFDN0IsT0FBTyxDQUFDLFNBQVMsQ0FBQyxHQUFHLENBQUMsd0JBQXdCLEdBQUcsYUFBYSxDQUFDLENBQUM7SUFDaEUsTUFBTSxDQUFDLFlBQVksQ0FBQyxVQUFVLENBQUMsYUFBYSxDQUFDLEVBQUUsS0FBSyxFQUFFLFlBQVksQ0FBQyxDQUFDLElBQUksQ0FBQztRQUNyRSxPQUFPLENBQUMsU0FBUyxDQUFDLEVBQUUsQ0FBQyx5QkFBeUIsQ0FBQyxDQUFDO1FBQ2hELE9BQU8sQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLDhEQUE4RCxDQUFDLENBQUM7UUFDdkYsUUFBUSxFQUFFLENBQUMsSUFBSSxDQUFDO1lBQ1osSUFBSSxDQUFDLE9BQU8sRUFB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

8
dist/cert.paths.d.ts vendored Normal file
View File

@ -0,0 +1,8 @@
export declare let certDir: string;
export declare let defaultSslDir: string;
export declare let assetDir: string;
export declare let accountsDir: string;
export declare let certHook: string;
export declare let config: string;
export declare let leShConfig: string;
export declare let letsencryptSh: string;

13
dist/cert.paths.js vendored Normal file
View File

@ -0,0 +1,13 @@
"use strict";
const plugins = require("./cert.plugins");
//dirs
exports.certDir = plugins.path.join(__dirname, "assets/certs");
exports.defaultSslDir = plugins.path.join(__dirname, "assets/defaultSslDir");
exports.assetDir = plugins.path.join(__dirname, "assets/");
exports.accountsDir = plugins.path.join(__dirname, "assets/accounts/");
// files
exports.certHook = plugins.path.join(__dirname, "cert.hook.js");
exports.config = plugins.path.join(__dirname, "assets/config.json");
exports.leShConfig = plugins.path.join(__dirname, "assets/leshconfig.json");
exports.letsencryptSh = plugins.path.join(__dirname, "assets/letsencrypt.sh");
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2VydC5wYXRocy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL2NlcnQucGF0aHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLE1BQVksT0FBTyxXQUFNLGdCQUFnQixDQUFDLENBQUE7QUFFMUMsTUFBTTtBQUNLLGVBQU8sR0FBRyxPQUFPLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUMsY0FBYyxDQUFDLENBQUM7QUFDdEQscUJBQWEsR0FBRyxPQUFPLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUMsc0JBQXNCLENBQUMsQ0FBQztBQUNwRSxnQkFBUSxHQUFHLE9BQU8sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBQyxTQUFTLENBQUMsQ0FBQztBQUNsRCxtQkFBVyxHQUFHLE9BQU8sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBQyxrQkFBa0IsQ0FBQyxDQUFDO0FBRXpFLFFBQVE7QUFDRyxnQkFBUSxHQUFHLE9BQU8sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBQyxjQUFjLENBQUMsQ0FBQztBQUN2RCxjQUFNLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFDLG9CQUFvQixDQUFDLENBQUM7QUFDM0Qsa0JBQVUsR0FBRyxPQUFPLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUMsd0JBQXdCLENBQUMsQ0FBQztBQUNuRSxxQkFBYSxHQUFHLE9BQU8sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBQyx1QkFBdUIsQ0FBQyxDQUFDIn0=

12
dist/cert.plugins.d.ts vendored Normal file
View File

@ -0,0 +1,12 @@
import "typings-global";
export import beautylog = require("beautylog");
export import cflare = require("cflare");
export declare let fs: any;
export import lik = require("lik");
export import path = require("path");
export import q = require("q");
export import shelljs = require("shelljs");
export import smartcli = require("smartcli");
export import smartfile = require("smartfile");
export import smartgit = require("smartgit");
export import smartstring = require("smartstring");

14
dist/cert.plugins.js vendored Normal file
View File

@ -0,0 +1,14 @@
"use strict";
require("typings-global");
exports.beautylog = require("beautylog");
exports.cflare = require("cflare");
exports.fs = require("fs-extra");
exports.lik = require("lik");
exports.path = require("path");
exports.q = require("q");
exports.shelljs = require("shelljs");
exports.smartcli = require("smartcli");
exports.smartfile = require("smartfile");
exports.smartgit = require("smartgit");
exports.smartstring = require("smartstring");
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2VydC5wbHVnaW5zLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvY2VydC5wbHVnaW5zLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQSxRQUFPLGdCQUFnQixDQUFDLENBQUE7QUFDVixpQkFBUyxXQUFXLFdBQVcsQ0FBQyxDQUFDO0FBQ2pDLGNBQU0sV0FBVyxRQUFRLENBQUMsQ0FBQztBQUM5QixVQUFFLEdBQUcsT0FBTyxDQUFDLFVBQVUsQ0FBQyxDQUFDO0FBQ3RCLFdBQUcsV0FBVyxLQUFLLENBQUMsQ0FBQztBQUNyQixZQUFJLFdBQVcsTUFBTSxDQUFDLENBQUM7QUFDdkIsU0FBQyxXQUFXLEdBQUcsQ0FBQyxDQUFDO0FBQ2pCLGVBQU8sV0FBVyxTQUFTLENBQUMsQ0FBQztBQUM3QixnQkFBUSxXQUFXLFVBQVUsQ0FBQyxDQUFDO0FBQy9CLGlCQUFTLFdBQVcsV0FBVyxDQUFDLENBQUM7QUFDakMsZ0JBQVEsV0FBVyxVQUFVLENBQUMsQ0FBQztBQUMvQixtQkFBVyxXQUFXLGFBQWEsQ0FBQyxDQUFDIn0=

3
dist/hook.js vendored
View File

@ -1,3 +0,0 @@
//# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IiIsImZpbGUiOiJob29rLmpzIiwic291cmNlc0NvbnRlbnQiOltdfQ==

44
dist/index.d.ts vendored
View File

@ -0,0 +1,44 @@
/// <reference types="q" />
import * as plugins from "./cert.plugins";
export interface ICertConstructorOptions {
cfEmail: string;
cfKey: string;
sslDir?: string;
gitOriginRepo?: string;
testMode?: boolean;
}
export declare class Cert {
private _cfEmail;
private _cfKey;
private _sslDir;
private _gitOriginRepo;
private _testMode;
domainsCurrentlyRequesting: plugins.lik.Stringmap;
certificatesPresent: Certificate[];
certificatesValid: Certificate[];
/**
* Constructor for Cert object
*/
constructor(optionsArg: ICertConstructorOptions);
/**
* Pulls already requested certificates from git origin
*/
sslGitOriginPull: () => void;
/**
* Pushes all new requested certificates to git origin
*/
sslGitOriginAddCommitPush: () => void;
/**
* gets a ssl cert for a given domain
*/
getDomainCert(domainNameArg: string, optionsArg?: {
force: boolean;
}): plugins.q.Promise<{}>;
cleanOldCertificates(): void;
}
export declare class Certificate {
domainName: string;
creationDate: Date;
expiryDate: Date;
constructor();
}

162
dist/index.js vendored

File diff suppressed because one or more lines are too long

3
dist/install.d.ts vendored
View File

@ -0,0 +1,3 @@
/// <reference types="q" />
import * as plugins from "./cert.plugins";
export declare let startInstall: () => plugins.q.Promise<{}>;

22
dist/install.js vendored
View File

@ -1,3 +1,19 @@
"use strict";
const plugins = require("./cert.plugins");
//# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IiIsImZpbGUiOiJpbnN0YWxsLmpzIiwic291cmNlc0NvbnRlbnQiOltdfQ== const paths = require("./cert.paths");
exports.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(exports.startInstall);
smartcli.startParse();
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5zdGFsbC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL2luc3RhbGwudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLE1BQVksT0FBTyxXQUFNLGdCQUFnQixDQUFDLENBQUE7QUFDMUMsTUFBWSxLQUFLLFdBQU0sY0FBYyxDQUFDLENBQUE7QUFFM0Isb0JBQVksR0FBRztJQUN0QixJQUFJLElBQUksR0FBRyxPQUFPLENBQUMsQ0FBQyxDQUFDLEtBQUssRUFBRSxDQUFDO0lBQzdCLE9BQU8sQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLHNDQUFzQyxDQUFDLENBQUM7SUFFL0QsT0FBTyxDQUFDLEVBQUUsQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLFNBQVMsQ0FBQyxDQUFDLENBQUM7SUFDOUQsT0FBTyxDQUFDLFNBQVMsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUN6QixrRkFBa0YsRUFDbEYsS0FBSyxDQUFDLGFBQWEsQ0FDdEIsQ0FBQyxJQUFJLENBQUM7UUFDSCxPQUFPLENBQUMsU0FBUyxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUNuQyxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUM7SUFDbkIsQ0FBQyxDQUFDLENBQUM7SUFDSCxNQUFNLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQztBQUN4QixDQUFDLENBQUM7QUFFRixJQUFJLFFBQVEsR0FBRyxJQUFJLE9BQU8sQ0FBQyxRQUFRLENBQUMsUUFBUSxFQUFFLENBQUM7QUFDL0MsUUFBUSxDQUFDLFVBQVUsQ0FBQztJQUNoQixXQUFXLEVBQUMsU0FBUztDQUN4QixDQUFDLENBQUMsSUFBSSxDQUFDLG9CQUFZLENBQUMsQ0FBQztBQUN0QixRQUFRLENBQUMsVUFBVSxFQUFFLENBQUMifQ==

View File

@ -1,14 +1,18 @@
{ {
"name": "cert", "name": "cert",
"version": "0.0.2", "version": "1.0.3",
"description": "automatic cert generation for coreos clusters", "description": "Easily obain SSL certificates from LetsEncrypt. Supports DNS-01 challenge. TypeScript ready.",
"main": "dist/index.js", "main": "dist/index.js",
"typings": "dist/index.d.ts",
"scripts": { "scripts": {
"test": "(npmts)" "test": "(npm run cleanTest && npmts)",
"cleanTest": "(rm -rf ./test/assets)",
"install": "node dist/install.js install",
"compile": "(npmts --notest)"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
"url": "git+https://github.com/pushrocks/cert.git" "url": "git+https://gitlab.com/pushrocks/cert.git"
}, },
"keywords": [ "keywords": [
"coreos", "coreos",
@ -19,13 +23,29 @@
"author": "Lossless GmbH", "author": "Lossless GmbH",
"license": "MIT", "license": "MIT",
"bugs": { "bugs": {
"url": "https://github.com/pushrocks/cert/issues" "url": "https://gitlab.com/pushrocks/cert/issues"
}, },
"homepage": "https://github.com/pushrocks/cert#readme", "homepage": "https://gitlab.com/pushrocks/cert#readme",
"dependencies": { "dependencies": {
"letsencrypt": "^1.4.4" "@types/minimatch": "^2.0.28",
"@types/q": "^0.0.27",
"@types/shelljs": "^0.3.27",
"beautylog": "^5.0.14",
"cflare": "0.0.9",
"fs-extra": "^0.30.0",
"lik": "^1.0.2",
"q": "^1.4.1",
"shelljs": "^0.7.0",
"smartcli": "^1.0.4",
"smartfile": "^4.0.12",
"smartgit": "0.1.9",
"smartstring": "^2.0.15",
"typings-global": "^1.0.6"
}, },
"devDependencies": { "devDependencies": {
"npmts-g": "^5.2.6" "npmts-g": "^5.2.6",
"qenv": "^1.0.8",
"should": "^10.0.0",
"typings-test": "^1.0.1"
} }
} }

3
qenv.yml Normal file
View File

@ -0,0 +1,3 @@
vars:
- CF_EMAIL
- CF_KEY

2
test/test.d.ts vendored Normal file
View File

@ -0,0 +1,2 @@
import "typings-test";
import "should";

47
test/test.js Normal file
View File

@ -0,0 +1,47 @@
"use strict";
require("typings-test");
require("should");
const qenv_1 = require("qenv");
const path = require("path");
const q = require("q");
const install_1 = require("../dist/install");
const cert = require("../dist/index");
let testQenv = new qenv_1.Qenv(process.cwd(), process.cwd() + "/.nogit");
let testCert;
describe("cert", function () {
describe("install", function () {
it("should download letsencrypt.sh", function (done) {
this.timeout(5000);
install_1.startInstall().then(() => {
done();
});
});
});
describe("Cert", function () {
it("should create a new Cert object from class", function () {
this.timeout(40000);
testCert = new cert.Cert({
cfEmail: process.env.CF_EMAIL,
cfKey: process.env.CF_KEY,
sslDir: path.join(process.cwd(), "test/assets"),
gitOriginRepo: "git@gitlab.com:sandboxzone/sandbox-sslorigin.git",
testMode: true
});
testCert.should.be.instanceof(cert.Cert);
});
it("should get a valid certificate", function (done) {
this.timeout(400000);
let promiseArray = [];
function getRandomArbitrary(min, max) {
return Math.floor(Math.random() * (max - min) + min);
}
promiseArray.push(testCert.getDomainCert(`testing${getRandomArbitrary(1, 100000)}.bleu.de`));
//promiseArray.push(testCert.getDomainCert(`testing${getRandomArbitrary(1,100000)}.bleu.de`));
//promiseArray.push(testCert.getDomainCert(`testing${getRandomArbitrary(1,100000)}.bleu.de`));
q.all(promiseArray).then(() => {
done();
});
});
});
});
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGVzdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbInRlc3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLFFBQU8sY0FBYyxDQUFDLENBQUE7QUFDdEIsUUFBTyxRQUFRLENBQUMsQ0FBQTtBQUNoQix1QkFBbUIsTUFBTSxDQUFDLENBQUE7QUFDMUIsTUFBTyxJQUFJLFdBQVcsTUFBTSxDQUFDLENBQUM7QUFDOUIsTUFBTyxDQUFDLFdBQVcsR0FBRyxDQUFDLENBQUM7QUFDeEIsMEJBQTJCLGlCQUFpQixDQUFDLENBQUE7QUFDN0MsTUFBWSxJQUFJLFdBQU0sZUFBZSxDQUFDLENBQUE7QUFHdEMsSUFBSSxRQUFRLEdBQUcsSUFBSSxXQUFJLENBQUMsT0FBTyxDQUFDLEdBQUcsRUFBRSxFQUFFLE9BQU8sQ0FBQyxHQUFHLEVBQUUsR0FBRyxTQUFTLENBQUMsQ0FBQztBQUVsRSxJQUFJLFFBQWtCLENBQUM7QUFFdkIsUUFBUSxDQUFDLE1BQU0sRUFBQztJQUNaLFFBQVEsQ0FBQyxTQUFTLEVBQUM7UUFDZixFQUFFLENBQUMsZ0NBQWdDLEVBQUMsVUFBUyxJQUFJO1lBQzdDLElBQUksQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUM7WUFDbkIsc0JBQVksRUFBRSxDQUFDLElBQUksQ0FBQztnQkFDaEIsSUFBSSxFQUFFLENBQUM7WUFDWCxDQUFDLENBQUMsQ0FBQTtRQUNOLENBQUMsQ0FBQyxDQUFBO0lBQ04sQ0FBQyxDQUFDLENBQUE7SUFDRixRQUFRLENBQUMsTUFBTSxFQUFDO1FBQ1osRUFBRSxDQUFDLDRDQUE0QyxFQUFDO1lBQzVDLElBQUksQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUM7WUFDcEIsUUFBUSxHQUFHLElBQUksSUFBSSxDQUFDLElBQUksQ0FBQztnQkFDckIsT0FBTyxFQUFFLE9BQU8sQ0FBQyxHQUFHLENBQUMsUUFBUTtnQkFDN0IsS0FBSyxFQUFFLE9BQU8sQ0FBQyxHQUFHLENBQUMsTUFBTTtnQkFDekIsTUFBTSxFQUFFLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLEdBQUcsRUFBRSxFQUFDLGFBQWEsQ0FBQztnQkFDOUMsYUFBYSxFQUFDLGtEQUFrRDtnQkFDaEUsUUFBUSxFQUFDLElBQUk7YUFDaEIsQ0FBQyxDQUFDO1lBQ0gsUUFBUSxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUM3QyxDQUFDLENBQUMsQ0FBQTtRQUNGLEVBQUUsQ0FBQyxnQ0FBZ0MsRUFBQyxVQUFTLElBQUk7WUFDN0MsSUFBSSxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsQ0FBQztZQUNyQixJQUFJLFlBQVksR0FBRyxFQUFFLENBQUM7WUFDdEIsNEJBQTRCLEdBQUcsRUFBRSxHQUFHO2dCQUNoQyxNQUFNLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLEdBQUcsQ0FBQyxHQUFHLEdBQUcsR0FBRyxDQUFDLEdBQUcsR0FBRyxDQUFDLENBQUM7WUFDekQsQ0FBQztZQUNELFlBQVksQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLGFBQWEsQ0FBQyxVQUFVLGtCQUFrQixDQUFDLENBQUMsRUFBQyxNQUFNLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQztZQUM1Riw4RkFBOEY7WUFDOUYsOEZBQThGO1lBQzlGLENBQUMsQ0FBQyxHQUFHLENBQUMsWUFBWSxDQUFDLENBQUMsSUFBSSxDQUFDO2dCQUNyQixJQUFJLEVBQUUsQ0FBQztZQUNYLENBQUMsQ0FBQyxDQUFDO1FBQ1AsQ0FBQyxDQUFDLENBQUE7SUFDTixDQUFDLENBQUMsQ0FBQTtBQUNOLENBQUMsQ0FBQyxDQUFDIn0=

49
test/test.ts Normal file
View File

@ -0,0 +1,49 @@
import "typings-test";
import "should";
import {Qenv} from "qenv";
import path = require("path");
import q = require("q");
import {startInstall} from "../dist/install";
import * as cert from "../dist/index";
let testQenv = new Qenv(process.cwd(), process.cwd() + "/.nogit");
let testCert:cert.Cert;
describe("cert",function(){
describe("install",function(){
it("should download letsencrypt.sh",function(done){
this.timeout(5000);
startInstall().then(() => {
done();
})
})
})
describe("Cert",function(){
it("should create a new Cert object from class",function(){
this.timeout(40000);
testCert = new cert.Cert({
cfEmail: process.env.CF_EMAIL,
cfKey: process.env.CF_KEY,
sslDir: path.join(process.cwd(),"test/assets"),
gitOriginRepo:"git@gitlab.com:sandboxzone/sandbox-sslorigin.git",
testMode:true
});
testCert.should.be.instanceof(cert.Cert);
})
it("should get a valid certificate",function(done){
this.timeout(400000);
let promiseArray = [];
function getRandomArbitrary(min, max) {
return Math.floor(Math.random() * (max - min) + min);
}
promiseArray.push(testCert.getDomainCert(`testing${getRandomArbitrary(1,100000)}.bleu.de`));
//promiseArray.push(testCert.getDomainCert(`testing${getRandomArbitrary(1,100000)}.bleu.de`));
//promiseArray.push(testCert.getDomainCert(`testing${getRandomArbitrary(1,100000)}.bleu.de`));
q.all(promiseArray).then(() => {
done();
});
})
})
});

25
ts/cert.helpers.ts Normal file
View File

@ -0,0 +1,25 @@
import {Cert} from "./index.ts";
import * as plugins from "./cert.plugins";
import * as paths from "./cert.paths";
let firstCall = true;
let enoughTime = false;
export let accountsKeyPresent = () => {
let done = plugins.q.defer();
if (firstCall) {
done.resolve();
firstCall = false;
}  else {
setTimeout(done.resolve,5000);
};
return done.promise;
};
export let scheduleRetry = (domainArg:string,certClassArg:Cert) => {
let done = plugins.q.defer();
setTimeout(() => {
certClassArg.getDomainCert(domainArg)
.then(done.resolve);
},20000);
return done.promise;
};

73
ts/cert.hook.ts Normal file
View File

@ -0,0 +1,73 @@
#!/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 paths from "./cert.paths";
let smartcli = new plugins.smartcli.Smartcli();
let config = plugins.smartfile.fs.toObjectSync(paths.config);
let cflare = new plugins.cflare.CflareAccount();
cflare.auth({
email: config.cfEmail,
key: config.cfKey
});
let setChallenge = (domainNameArg: string, challengeArg: string) => {
let done = plugins.q.defer();
plugins.beautylog.log("setting challenge for " + domainNameArg);
cflare.createRecord(prefixName(domainNameArg), "TXT", challengeArg).then(() => {
plugins.beautylog.ok("Challenge has been set!");
plugins.beautylog.info("We need to cool down to let DNS propagate to edge locations!");
cooldown().then(() => {
done.resolve();
});
});
return done.promise;
}
let cleanChallenge = (domainNameArg) => {
let done = plugins.q.defer();
plugins.beautylog.log("cleaning challenge for " + domainNameArg);
cflare.removeRecord(prefixName(domainNameArg), "TXT");
return done.promise;
}
let cooldown = () => {
let done = plugins.q.defer();
let cooldowntime = 40000;
let passedTime = 0;
plugins.beautylog.log("Cooling down! " + (cooldowntime/1000).toString() + " seconds left");
let coolDownCounter = () => {
setTimeout(() => {
if(cooldowntime <= passedTime){
plugins.beautylog.ok("Cooled down!");
done.resolve();
} else {
passedTime = passedTime + 5000;
plugins.beautylog.log("Cooling down! " + ((cooldowntime - passedTime)/1000).toString() + " seconds left");
coolDownCounter();
}
}, 5000);
}
coolDownCounter();
return done.promise;
}
let prefixName = (domainNameArg: string): string => {
return "_acme-challenge." + domainNameArg;
}
smartcli.addCommand({
commandName: "deploy_challenge"
}).then((argv) => {
setChallenge(argv._[1], argv._[3]);
});
smartcli.addCommand({
commandName: "clean_challenge"
}).then((argv) => {
cleanChallenge(argv._[1]);
});
smartcli.startParse();

14
ts/cert.paths.ts Normal file
View File

@ -0,0 +1,14 @@
import * as plugins from "./cert.plugins";
//dirs
export let certDir = plugins.path.join(__dirname,"assets/certs");
export let defaultSslDir = plugins.path.join(__dirname,"assets/defaultSslDir");
export let assetDir = plugins.path.join(__dirname,"assets/");
export let accountsDir = plugins.path.join(__dirname,"assets/accounts/");
// files
export let certHook = plugins.path.join(__dirname,"cert.hook.js");
export let config = plugins.path.join(__dirname,"assets/config.json");
export let leShConfig = plugins.path.join(__dirname,"assets/leshconfig.json");
export let letsencryptSh = plugins.path.join(__dirname,"assets/letsencrypt.sh");

13
ts/cert.plugins.ts Normal file
View File

@ -0,0 +1,13 @@
import "typings-global";
export import beautylog = require("beautylog");
export import cflare = require("cflare");
export let fs = require("fs-extra");
export import lik = require("lik");
export import path = require("path");
export import q = require("q");
export import shelljs = require("shelljs");
export import smartcli = require("smartcli");
export import smartfile = require("smartfile");
export import smartgit = require("smartgit");
export import smartstring = require("smartstring");

View File

View File

@ -0,0 +1,205 @@
import * as plugins from "./cert.plugins";
import * as paths from "./cert.paths";
import * as helpers from "./cert.helpers"
export interface ICertConstructorOptions {
cfEmail: string,
cfKey: string,
sslDir?: string,
gitOriginRepo?: string,
testMode?: boolean
};
export class Cert {
private _cfEmail: string;
private _cfKey: string;
private _sslDir: string;
private _gitOriginRepo: string;
private _testMode: boolean;
domainsCurrentlyRequesting: plugins.lik.Stringmap = new plugins.lik.Stringmap();
certificatesPresent: Certificate[];
certificatesValid: Certificate[];
/**
* Constructor for Cert object
*/
constructor(optionsArg: ICertConstructorOptions) {
this._cfEmail = optionsArg.cfEmail;
this._cfKey = optionsArg.cfKey;
this._sslDir = optionsArg.sslDir;
this._gitOriginRepo = optionsArg.gitOriginRepo;
this._testMode = optionsArg.testMode;
// write hook config
let config = {
cfEmail: this._cfEmail,
cfKey: this._cfKey
}
plugins.smartfile.memory.toFsSync(
JSON.stringify(config),
plugins.path.join(__dirname, "assets/config.json")
);
// setup sslDir
if (!this._sslDir) this._sslDir = paths.defaultSslDir;
// setup Git
if (this._gitOriginRepo) {
plugins.smartgit.init(this._sslDir);
plugins.smartgit.remote.add(this._sslDir, "origin", this._gitOriginRepo);
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);
};
/**
* Pulls already requested certificates from git origin
*/
sslGitOriginPull = () => {
if (this._gitOriginRepo) {
plugins.smartgit.pull(this._sslDir, "origin", "master");
}
};
/**
* Pushes all new requested certificates to git origin
*/
sslGitOriginAddCommitPush = () => {
if (this._gitOriginRepo) {
plugins.smartgit.add.addAll(this._sslDir);
plugins.smartgit.commit(this._sslDir, "added new SSL certificates and deleted obsolete ones.");
plugins.smartgit.push(this._sslDir, "origin", "master");
}
};
/**
* gets a ssl cert for a given domain
*/
getDomainCert(domainNameArg: string, optionsArg: { force: boolean } = { force: false }) {
let done = plugins.q.defer();
// make sure no one else requires the same domain at the same time
helpers.accountsKeyPresent().then(() => {
if (!this.domainsCurrentlyRequesting.checkString(domainNameArg)) {
this.domainsCurrentlyRequesting.addString(domainNameArg);
if (!checkDomainsStillValid(domainNameArg, this._sslDir) || optionsArg.force) {
plugins.smartfile.fs.ensureDir(paths.certDir);
plugins.beautylog.info(`getting cert for ${domainNameArg}`);
plugins.shelljs.exec(
`bash -c "${paths.letsencryptSh} -c --no-lock -f ${paths.leShConfig} -d ${domainNameArg} -t dns-01 -k ${paths.certHook} -o ${paths.certDir}"`,
{
silent: true
},
(codeArg, stdoutArg) => {
if (codeArg == 0) {
console.log(stdoutArg);
let fetchedCertsArray: string[] = plugins.smartfile.fs.listFoldersSync(paths.certDir);
if (fetchedCertsArray.indexOf(domainNameArg) != -1) {
updateSslDirSync(this._sslDir, domainNameArg);
plugins.smartfile.fs.removeSync(plugins.path.join(paths.certDir, domainNameArg));
}
this.domainsCurrentlyRequesting.removeString(domainNameArg);
done.resolve();
} else {
this.domainsCurrentlyRequesting.removeString(domainNameArg);
plugins.beautylog.warn(`${domainNameArg} scheduled for retry`);
helpers.scheduleRetry(domainNameArg,this).then(done.resolve);
}
}
);
} else {
plugins.beautylog.info("certificate for " + domainNameArg + " is still valid! Not fetching new one!");
this.domainsCurrentlyRequesting.removeString(domainNameArg);
done.resolve();
};
} else {
plugins.beautylog.warn(`${domainNameArg} is already requesting`);
};
});
return done.promise;
};
cleanOldCertificates() {
};
}
export class Certificate {
domainName: string;
creationDate: Date;
expiryDate: Date;
constructor() {
};
}
interface certConfig {
domainName: string;
created: number;
expires: number;
}
let checkDomainsStillValid = (domainNameArg: string, sslDirArg: string): boolean => {
let domainConfigPath = plugins.path.join(sslDirArg, domainNameArg, "config.json");
if (plugins.smartfile.fs.fileExistsSync(domainConfigPath)) {
let domainConfig = plugins.smartfile.fs.toObjectSync(
domainConfigPath,
"json"
);
if (Date.now() >= ((domainConfig.expires - 604800) * 1000)) {
return false;
} else {
return true;
}
} else {
return false;
}
}
let updateSslDirSync = (sslDirArg: string, domainNameArg: string) => {
plugins.smartfile.fs.ensureDirSync(sslDirArg);
let domainCertFolder = plugins.path.join(paths.certDir, domainNameArg)
if (plugins.smartfile.fs.listFoldersSync(paths.certDir).indexOf(domainNameArg) != -1) {
plugins.smartfile.fs.copySync(
plugins.path.join(domainCertFolder, "fullchain.pem"),
plugins.path.join(sslDirArg, domainNameArg, "fullchain.pem")
);
plugins.smartfile.fs.copySync(
plugins.path.join(domainCertFolder, "privkey.pem"),
plugins.path.join(sslDirArg, domainNameArg, "privkey.pem")
);
// create cert config
let certRegex = /.*\-([0-9]*)\.pem/;
let certFileNameWithTime: string = plugins.smartfile.fs.listFilesSync(domainCertFolder, certRegex)[0];
let certTime = parseInt(certRegex.exec(certFileNameWithTime)[1]);
let certConfig: certConfig = {
domainName: domainNameArg,
created: certTime,
expires: certTime + 7776000
};
plugins.smartfile.memory.toFsSync(
JSON.stringify(certConfig),
plugins.path.join(sslDirArg, domainNameArg, "config.json")
);
};
}
const enum gitSyncDirection {
toOrigin,
fromOrigin
}
let updateGitOrigin = (syncDirectionArg: gitSyncDirection) => {
};
updateGitOrigin(gitSyncDirection.toOrigin);

View File

@ -0,0 +1,23 @@
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();