Compare commits

...

26 Commits

Author SHA1 Message Date
bf07bf27d4 switch to new org scheme 2023-07-11 00:21:17 +02:00
5117d1e3c3 switch to new org scheme 2023-07-10 02:42:26 +02:00
b8ecc0bca0 added smartacme 2017-01-03 08:15:09 +01:00
34299fa651 remove npm letsencrypt 2017-01-01 14:25:46 +01:00
fd89e54295 fix 2017-01-01 05:18:50 +01:00
7455891097 switch to new storage strategy... 2016-10-24 03:26:34 +02:00
944fbc071b fix .gitignore 2016-10-24 02:42:45 +02:00
b6b06e6853 update 2016-10-24 02:24:34 +02:00
c4b72aebf8 update 2016-10-24 01:42:31 +02:00
b72f6dfac3 1.0.8 2016-10-24 01:06:30 +02:00
aa85d294c5 add some classes 2016-10-24 01:06:27 +02:00
b03d8bfb65 fix 2016-10-24 00:35:00 +02:00
4094834446 fix 2016-10-22 16:27:57 +02:00
5c7bf24c56 start transition to letsencrypt 2016-10-22 16:21:25 +02:00
738c249a3e add npmextra.json 2016-10-22 15:46:04 +02:00
b8656aa231 update README 2016-10-22 04:23:12 +02:00
903b497525 update dependencies 2016-10-22 04:16:07 +02:00
2c9f19b2e5 1.0.7 2016-08-03 12:26:48 +02:00
1c63450213 update version types 2016-08-03 12:26:34 +02:00
1beceb21a8 1.0.6 2016-07-24 20:26:20 +02:00
ec40f43c9e fix README and git 2016-07-24 20:17:23 +02:00
a4d0654f28 improve gitlab ci 2016-07-24 20:07:24 +02:00
3ca368755b 1.0.5 2016-07-24 19:56:36 +02:00
86fedee9ed now recovering from errors 2016-07-24 19:56:32 +02:00
fc91384a76 1.0.4 2016-07-24 19:39:23 +02:00
2e8cfd00d2 now paying respect to same zone subdomains 2016-07-24 19:39:20 +02:00
43 changed files with 2901 additions and 802 deletions

5
.gitignore vendored
View File

@ -1,5 +1,8 @@
node_modules
node_modules/
assets/
docs/
public/
pages/
coverage/
.nogit/
dist/assets/

View File

@ -4,7 +4,10 @@ stages:
- test1
- test2
- release
before_script:
- npmci prepare ssh
testLTS:
stage: test1
script:

View File

@ -1,8 +1,21 @@
# Cert
Easily obain SSL certificates from LetsEncrypt. Supports DNS-01 challenge. TypeScript ready.
## Status
## Availabililty
[![npm](https://push.rocks/assets/repo-button-npm.svg)](https://www.npmjs.com/package/cert)
[![git](https://push.rocks/assets/repo-button-git.svg)](https://gitlab.com/pushrocks/cert)
[![git](https://push.rocks/assets/repo-button-mirror.svg)](https://github.com/pushrocks/cert)
[![docs](https://push.rocks/assets/repo-button-docs.svg)](https://pushrocks.gitlab.io/cert/)
## Status for master
[![build status](https://gitlab.com/pushrocks/cert/badges/master/build.svg)](https://gitlab.com/pushrocks/cert/commits/master)
[![coverage report](https://gitlab.com/pushrocks/cert/badges/master/coverage.svg)](https://gitlab.com/pushrocks/cert/commits/master)
[![Dependency Status](https://david-dm.org/pushrocks/cert.svg)](https://david-dm.org/pushrocks/cert)
[![bitHound Dependencies](https://www.bithound.io/github/pushrocks/cert/badges/dependencies.svg)](https://www.bithound.io/github/pushrocks/cert/master/dependencies/npm)
[![bitHound Code](https://www.bithound.io/github/pushrocks/cert/badges/code.svg)](https://www.bithound.io/github/pushrocks/cert)
[![TypeScript](https://img.shields.io/badge/TypeScript-2.x-blue.svg)](https://nodejs.org/dist/latest-v6.x/docs/api/)
[![node](https://img.shields.io/badge/node->=%206.x.x-blue.svg)](https://nodejs.org/dist/latest-v6.x/docs/api/)
[![JavaScript Style Guide](https://img.shields.io/badge/code%20style-standard-brightgreen.svg)](http://standardjs.com/)
## Usage
@ -19,7 +32,9 @@ let myCert = new Cert({
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.
> **Note:** cert supports async parallel cert fetching.
However any subsequent calls will wait for the queue of the same dns zone to clear.
In other words: test1.domain1.tld and test2.domain2.tld will run in parallel, but test2.domain1.tld will wait for test1.domain1.tld !
## sslDir
to use the certificates it is important to understand what the structure of the ssl directory looks like.
@ -33,7 +48,4 @@ that handles SSL managemet for you. But even the proxy needs to be updated from
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.
[![npm](https://push.rocks/assets/repo-header.svg)](https://push.rocks)

43
dist/cert.classes.cert.d.ts vendored Normal file
View File

@ -0,0 +1,43 @@
/// <reference types="q" />
import * as q from 'q';
import { Stringmap, Objectmap } from 'lik';
import { Certificate } from './cert.classes.certificate';
import { Letsencrypt, TLeEnv } from './cert.classes.letsencrypt';
export interface ICertConstructorOptions {
cfEmail: string;
cfKey: string;
sslDirPath?: string;
gitOriginRepo?: string;
leEnv?: TLeEnv;
}
export declare class Cert {
domainStringRequestMap: Stringmap;
certificateMap: Objectmap<Certificate>;
letsencrypt: Letsencrypt;
private _challengeHandler;
private _certRepo;
/**
* Constructor for Cert object
*/
constructor(optionsArg: ICertConstructorOptions);
/**
* setup the Cert instanceof
* @executes ASYNC
* @return Promise
*/
setup(): q.Promise<{}>;
/**
* adds a Certificate for a given domain
*/
addCertificate(domainNameArg: string, optionsArg?: {
force: boolean;
}): q.Promise<{}>;
/**
* cleans up old certificates
*/
cleanOldCertificates(): void;
/**
* executes the current batch of jobs
*/
deploy(): void;
}

75
dist/cert.classes.cert.js vendored Normal file
View File

@ -0,0 +1,75 @@
"use strict";
const q = require("q");
const lik_1 = require("lik");
// classes
const cert_classes_certificate_1 = require("./cert.classes.certificate");
const cert_classes_certrepo_1 = require("./cert.classes.certrepo");
const cert_classes_letsencrypt_1 = require("./cert.classes.letsencrypt");
const cert_classes_challengehandler_1 = require("./cert.classes.challengehandler");
class Cert {
/**
* Constructor for Cert object
*/
constructor(optionsArg) {
this.domainStringRequestMap = new lik_1.Stringmap();
this.certificateMap = new lik_1.Objectmap();
// set up challengehandler
this._challengeHandler = new cert_classes_challengehandler_1.ChallengeHandler({
cfEmail: optionsArg.cfEmail,
cfKey: optionsArg.cfKey
});
// setup Letsencrypt
this.letsencrypt = new cert_classes_letsencrypt_1.Letsencrypt({
leEnv: optionsArg.leEnv,
sslDir: optionsArg.sslDirPath,
challengeHandler: this._challengeHandler
});
this._certRepo = new cert_classes_certrepo_1.CertRepo({
sslDirPath: optionsArg.sslDirPath,
remoteGitUrl: optionsArg.gitOriginRepo,
certInstance: this
});
}
/**
* setup the Cert instanceof
* @executes ASYNC
* @return Promise
*/
setup() {
return this._certRepo.setup();
}
/**
* adds a Certificate for a given domain
*/
addCertificate(domainNameArg, optionsArg = { force: false }) {
let done = q.defer();
let certificateForDomain = this.certificateMap.find((certificate) => {
return certificate.domainName === domainNameArg;
});
if (certificateForDomain instanceof cert_classes_certificate_1.Certificate) {
certificateForDomain.renew()
.then(done.resolve);
}
else {
certificateForDomain = new cert_classes_certificate_1.Certificate({
certInstance: this,
domainName: domainNameArg
});
certificateForDomain.renew()
.then(done.resolve);
}
return done.promise;
}
/**
* cleans up old certificates
*/
cleanOldCertificates() {
}
/**
* executes the current batch of jobs
*/
deploy() {
}
}
exports.Cert = Cert;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2VydC5jbGFzc2VzLmNlcnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9jZXJ0LmNsYXNzZXMuY2VydC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUEsdUJBQXNCO0FBQ3RCLDZCQUEwQztBQUsxQyxVQUFVO0FBQ1YseUVBQXdEO0FBQ3hELG1FQUFrRDtBQUNsRCx5RUFBZ0U7QUFDaEUsbUZBQWtFO0FBV2xFO0lBT0k7O09BRUc7SUFDSCxZQUFZLFVBQW1DO1FBVC9DLDJCQUFzQixHQUFHLElBQUksZUFBUyxFQUFFLENBQUE7UUFDeEMsbUJBQWMsR0FBRyxJQUFJLGVBQVMsRUFBZSxDQUFBO1FBVXpDLDBCQUEwQjtRQUMxQixJQUFJLENBQUMsaUJBQWlCLEdBQUcsSUFBSSxnREFBZ0IsQ0FBQztZQUMxQyxPQUFPLEVBQUUsVUFBVSxDQUFDLE9BQU87WUFDM0IsS0FBSyxFQUFFLFVBQVUsQ0FBQyxLQUFLO1NBQzFCLENBQUMsQ0FBQTtRQUVGLG9CQUFvQjtRQUNwQixJQUFJLENBQUMsV0FBVyxHQUFHLElBQUksc0NBQVcsQ0FBQztZQUMvQixLQUFLLEVBQUUsVUFBVSxDQUFDLEtBQUs7WUFDdkIsTUFBTSxFQUFFLFVBQVUsQ0FBQyxVQUFVO1lBQzdCLGdCQUFnQixFQUFFLElBQUksQ0FBQyxpQkFBaUI7U0FDM0MsQ0FBQyxDQUFBO1FBRUYsSUFBSSxDQUFDLFNBQVMsR0FBRyxJQUFJLGdDQUFRLENBQUM7WUFDMUIsVUFBVSxFQUFFLFVBQVUsQ0FBQyxVQUFVO1lBQ2pDLFlBQVksRUFBRSxVQUFVLENBQUMsYUFBYTtZQUN0QyxZQUFZLEVBQUUsSUFBSTtTQUNyQixDQUFDLENBQUE7SUFDTixDQUFDO0lBRUQ7Ozs7T0FJRztJQUNILEtBQUs7UUFDRCxNQUFNLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxLQUFLLEVBQUUsQ0FBQTtJQUNqQyxDQUFDO0lBRUQ7O09BRUc7SUFDSCxjQUFjLENBQUMsYUFBcUIsRUFBRSxhQUFpQyxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUU7UUFDbkYsSUFBSSxJQUFJLEdBQUcsQ0FBQyxDQUFDLEtBQUssRUFBRSxDQUFBO1FBQ3BCLElBQUksb0JBQW9CLEdBQUcsSUFBSSxDQUFDLGNBQWMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxXQUFXO1lBQzVELE1BQU0sQ0FBQyxXQUFXLENBQUMsVUFBVSxLQUFLLGFBQWEsQ0FBQTtRQUNuRCxDQUFDLENBQUMsQ0FBQTtRQUNGLEVBQUUsQ0FBQyxDQUFDLG9CQUFvQixZQUFZLHNDQUFXLENBQUMsQ0FBQyxDQUFDO1lBQzlDLG9CQUFvQixDQUFDLEtBQUssRUFBRTtpQkFDdkIsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQTtRQUMzQixDQUFDO1FBQUMsSUFBSSxDQUFDLENBQUM7WUFDSixvQkFBb0IsR0FBRyxJQUFJLHNDQUFXLENBQUM7Z0JBQ25DLFlBQVksRUFBRSxJQUFJO2dCQUNsQixVQUFVLEVBQUUsYUFBYTthQUM1QixDQUFDLENBQUE7WUFDRixvQkFBb0IsQ0FBQyxLQUFLLEVBQUU7aUJBQ3ZCLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUE7UUFDM0IsQ0FBQztRQUNELE1BQU0sQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFBO0lBQ3ZCLENBQUM7SUFFRDs7T0FFRztJQUNILG9CQUFvQjtJQUVwQixDQUFDO0lBRUQ7O09BRUc7SUFDSCxNQUFNO0lBRU4sQ0FBQztDQUNKO0FBNUVELG9CQTRFQyJ9

48
dist/cert.classes.certificate.d.ts vendored Normal file
View File

@ -0,0 +1,48 @@
/// <reference types="q" />
import * as q from 'q';
import * as plugins from './cert.plugins';
import { Cert } from './cert.classes.cert';
export interface ICertificateFsConfig {
domainName: string;
creationTime: number;
expiryTime: number;
}
export interface ICertificateConstructorOptions {
domainName: string;
certInstance: Cert;
}
export declare type TCertificateStatus = 'unregistered' | 'valid' | 'expiring' | 'expired';
export declare class Certificate {
domainName: string;
certInstance: Cert;
domainData: plugins.smartstring.Domain;
creationDate: Date;
expiryDate: Date;
publicKey: string;
privKey: string;
/**
* run when creating a new instance of Certificate
*/
constructor(optionsArg: ICertificateConstructorOptions);
/**
* the status of the Certificate
*/
readonly status: TCertificateStatus;
readonly sameZoneRequesting: boolean;
/**
* schedule a retry of certificate request
*/
scheduleRetry(): q.Promise<{}>;
/**
* renew certificate if needed
*/
renew(force?: boolean): q.Promise<{}>;
/**
* syncFs syncs the certificate with disk
*/
syncFs(): void;
/**
* deletes the certificate
*/
delete(): void;
}

103
dist/cert.classes.certificate.js vendored Normal file
View File

@ -0,0 +1,103 @@
"use strict";
const q = require("q");
const plugins = require("./cert.plugins");
class Certificate {
/**
* run when creating a new instance of Certificate
*/
constructor(optionsArg) {
this.creationDate = null;
this.expiryDate = null;
this.publicKey = null;
this.privKey = null;
this.domainName = optionsArg.domainName;
this.domainData = new plugins.smartstring.Domain(this.domainName);
this.certInstance = optionsArg.certInstance;
}
/**
* the status of the Certificate
*/
get status() {
let validTimeRemaining = 0;
if (this.creationDate !== null && this.expiryDate !== null) {
validTimeRemaining = this.expiryDate.getTime() - Date.now();
}
let MonthMilliseconds = 2629746000;
if (this.publicKey === null || this.privKey === null) {
return 'unregistered';
}
else if (validTimeRemaining >= MonthMilliseconds) {
return 'valid';
}
else if (validTimeRemaining < MonthMilliseconds && validTimeRemaining >= 0) {
return 'expiring';
}
else {
return 'expired';
}
}
get sameZoneRequesting() {
return this.certInstance.domainStringRequestMap.checkMinimatch('*' + this.domainData.zoneName);
}
/**
* schedule a retry of certificate request
*/
scheduleRetry() {
let done = plugins.q.defer();
setTimeout(() => {
this.renew()
.then(done.resolve);
}, 60000);
return done.promise;
}
/**
* renew certificate if needed
*/
renew(force = false) {
let done = q.defer();
if (this.status === 'valid') {
plugins.beautylog.log('Certificate still valid for more than 1 month, so it is not renewed now');
done.resolve();
}
else if (this.status === 'expiring' || this.status === 'expired' || this.status === 'unregistered') {
plugins.beautylog.info('Certificate not valid currently, going to renew now!');
if (this.sameZoneRequesting) {
this.certInstance.domainStringRequestMap.registerUntilTrue(() => {
return !this.sameZoneRequesting;
}, () => {
this.renew().then(done.resolve);
});
}
else {
this.certInstance.letsencrypt.registerDomain(this.domainName)
.then(() => {
return this.syncFs();
})
.then(() => {
done.resolve();
}).catch((err) => { console.log(err); });
}
}
else {
throw Error(`weird status for certificate with domain name ${this.domainName}`);
}
done.resolve();
return done.promise;
}
/**
* syncFs syncs the certificate with disk
*/
syncFs() {
let configJsonMemory = {
domainName: this.domainName,
creationTime: this.creationDate.getTime(),
expiryTime: this.expiryDate.getTime()
};
}
/**
* deletes the certificate
*/
delete() { }
}
exports.Certificate = Certificate;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2VydC5jbGFzc2VzLmNlcnRpZmljYXRlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvY2VydC5jbGFzc2VzLmNlcnRpZmljYXRlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQSx1QkFBc0I7QUFFdEIsMENBQXlDO0FBcUJ6QztJQVNJOztPQUVHO0lBQ0gsWUFBWSxVQUEwQztRQVJ0RCxpQkFBWSxHQUFTLElBQUksQ0FBQTtRQUN6QixlQUFVLEdBQVMsSUFBSSxDQUFBO1FBQ3ZCLGNBQVMsR0FBVyxJQUFJLENBQUE7UUFDeEIsWUFBTyxHQUFXLElBQUksQ0FBQTtRQU1sQixJQUFJLENBQUMsVUFBVSxHQUFHLFVBQVUsQ0FBQyxVQUFVLENBQUE7UUFDdkMsSUFBSSxDQUFDLFVBQVUsR0FBRyxJQUFJLE9BQU8sQ0FBQyxXQUFXLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FBQTtRQUNqRSxJQUFJLENBQUMsWUFBWSxHQUFHLFVBQVUsQ0FBQyxZQUFZLENBQUE7SUFDL0MsQ0FBQztJQUVEOztPQUVHO0lBQ0gsSUFBSSxNQUFNO1FBQ04sSUFBSSxrQkFBa0IsR0FBVyxDQUFDLENBQUE7UUFDbEMsRUFBRSxDQUFDLENBQUMsSUFBSSxDQUFDLFlBQVksS0FBSyxJQUFJLElBQUksSUFBSSxDQUFDLFVBQVUsS0FBSyxJQUFJLENBQUMsQ0FBQyxDQUFDO1lBQ3hELGtCQUFrQixHQUFHLElBQUksQ0FBQyxVQUFVLENBQUMsT0FBTyxFQUFFLEdBQUcsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFBO1FBQ2hFLENBQUM7UUFDRCxJQUFJLGlCQUFpQixHQUFHLFVBQVUsQ0FBQTtRQUNsQyxFQUFFLENBQUMsQ0FBQyxJQUFJLENBQUMsU0FBUyxLQUFLLElBQUksSUFBSSxJQUFJLENBQUMsT0FBTyxLQUFLLElBQUksQ0FBQyxDQUFDLENBQUM7WUFDbkQsTUFBTSxDQUFDLGNBQWMsQ0FBQTtRQUN6QixDQUFDO1FBQUMsSUFBSSxD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

31
dist/cert.classes.certrepo.d.ts vendored Normal file
View File

@ -0,0 +1,31 @@
/// <reference types="q" />
import * as q from 'q';
import { Cert } from './cert.classes.cert';
export interface ICertRepoConstructorOptions {
sslDirPath: string;
remoteGitUrl: string;
certInstance: Cert;
}
export declare class CertRepo {
private _sslDirPath;
private _remoteGitUrl;
private gitRepo;
private _certInstance;
constructor(optionsArg: ICertRepoConstructorOptions);
/**
* setup the Cert instance
*/
setup(): q.Promise<{}>;
/**
* syncs an objectmap of Certificates with repo
*/
syncFs(): q.Promise<{}>;
/**
* Pulls already requested certificates from git origin
*/
sslGitOriginPull: () => void;
/**
* Pushes all new requested certificates to git origin
*/
sslGitOriginAddCommitPush: () => void;
}

59
dist/cert.classes.certrepo.js vendored Normal file
View File

@ -0,0 +1,59 @@
"use strict";
const q = require("q");
const plugins = require("./cert.plugins");
const paths = require("./cert.paths");
class CertRepo {
constructor(optionsArg) {
/**
* Pulls already requested certificates from git origin
*/
this.sslGitOriginPull = () => {
if (this.gitRepo) {
this.gitRepo.pull('origin', 'master');
}
};
/**
* Pushes all new requested certificates to git origin
*/
this.sslGitOriginAddCommitPush = () => {
if (this._remoteGitUrl) {
this.gitRepo.addAll();
this.gitRepo.commit('added new SSL certificates and deleted obsolete ones.');
this.gitRepo.push('origin', 'master');
}
};
this._sslDirPath = optionsArg.sslDirPath;
this._remoteGitUrl = optionsArg.remoteGitUrl;
this._certInstance = optionsArg.certInstance;
// setup sslDir
if (!this._sslDirPath) {
this._sslDirPath = paths.defaultSslDir;
}
}
/**
* setup the Cert instance
*/
setup() {
// setup Git
let done = q.defer();
if (this._remoteGitUrl) {
plugins.smartfile.fs.ensureEmptyDirSync(paths.defaultSslDir);
plugins.smartgit.createRepoFromClone(this._remoteGitUrl, paths.defaultSslDir)
.then(gitRepoArg => {
this.gitRepo = gitRepoArg;
done.resolve();
});
}
return done.promise;
}
/**
* syncs an objectmap of Certificates with repo
*/
syncFs() {
let done = q.defer();
done.resolve();
return done.promise;
}
}
exports.CertRepo = CertRepo;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2VydC5jbGFzc2VzLmNlcnRyZXBvLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvY2VydC5jbGFzc2VzLmNlcnRyZXBvLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQSx1QkFBc0I7QUFHdEIsMENBQXlDO0FBQ3pDLHNDQUFxQztBQVdyQztJQUtJLFlBQVksVUFBdUM7UUFxQ25EOztXQUVHO1FBQ0gscUJBQWdCLEdBQUc7WUFDZixFQUFFLENBQUMsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQztnQkFDZixJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxRQUFRLEVBQUUsUUFBUSxDQUFDLENBQUE7WUFDekMsQ0FBQztRQUNMLENBQUMsQ0FBQTtRQUVEOztXQUVHO1FBQ0gsOEJBQXlCLEdBQUc7WUFDeEIsRUFBRSxDQUFDLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxDQUFDLENBQUM7Z0JBQ3JCLElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxFQUFFLENBQUE7Z0JBQ3JCLElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLHVEQUF1RCxDQUFDLENBQUE7Z0JBQzVFLElBQUksQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLFFBQVEsRUFBRSxRQUFRLENBQUMsQ0FBQTtZQUN6QyxDQUFDO1FBQ0wsQ0FBQyxDQUFBO1FBdERHLElBQUksQ0FBQyxXQUFXLEdBQUcsVUFBVSxDQUFDLFVBQVUsQ0FBQTtRQUN4QyxJQUFJLENBQUMsYUFBYSxHQUFHLFVBQVUsQ0FBQyxZQUFZLENBQUE7UUFDNUMsSUFBSSxDQUFDLGFBQWEsR0FBRyxVQUFVLENBQUMsWUFBWSxDQUFBO1FBRTVDLGVBQWU7UUFDZixFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUFDO1lBQ3BCLElBQUksQ0FBQyxXQUFXLEdBQUcsS0FBSyxDQUFDLGFBQWEsQ0FBQTtRQUMxQyxDQUFDO0lBQ0wsQ0FBQztJQUVEOztPQUVHO0lBQ0gsS0FBSztRQUNELFlBQVk7UUFDWixJQUFJLElBQUksR0FBRyxDQUFDLENBQUMsS0FBSyxFQUFFLENBQUE7UUFDcEIsRUFBRSxDQUFDLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxDQUFDLENBQUM7WUFDckIsT0FBTyxDQUFDLFNBQVMsQ0FBQyxFQUFFLENBQUMsa0JBQWtCLENBQUMsS0FBSyxDQUFDLGFBQWEsQ0FBQyxDQUFBO1lBQzVELE9BQU8sQ0FBQyxRQUFRLENBQUMsbUJBQW1CLENBQUMsSUFBSSxDQUFDLGFBQWEsRUFBRSxLQUFLLENBQUMsYUFBYSxDQUFDO2lCQUN4RSxJQUFJLENBQUMsVUFBVTtnQkFDWixJQUFJLENBQUMsT0FBTyxHQUFHLFVBQVUsQ0FBQTtnQkFDekIsSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFBO1lBQ2xCLENBQUMsQ0FBQyxDQUFBO1FBQ1YsQ0FBQztRQUNELE1BQU0sQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFBO0lBQ3ZCLENBQUM7SUFFRDs7T0FFRztJQUNILE1BQU07UUFDRixJQUFJLElBQUksR0FBRyxDQUFDLENBQUMsS0FBSyxFQUFFLENBQUE7UUFDcEIsSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFBO1FBQ2QsTUFBTSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUE7SUFDdkIsQ0FBQztDQXFCSjtBQTdERCw0QkE2REMifQ==

20
dist/cert.classes.challengehandler.d.ts vendored Normal file
View File

@ -0,0 +1,20 @@
/// <reference types="q" />
export interface IChallengehandlerConstructorOptions {
cfEmail: string;
cfKey: string;
}
/**
* class ChallengeHandler handles challenges
*/
export declare class ChallengeHandler {
private _cfInstance;
constructor(optionsArg: IChallengehandlerConstructorOptions);
/**
* set a challenge
*/
setChallenge(domainNameArg: string, challengeArg: string): Q.Promise<{}>;
/**
* cleans a challenge
*/
cleanChallenge(domainNameArg: any): Q.Promise<{}>;
}

75
dist/cert.classes.challengehandler.js vendored Normal file
View File

@ -0,0 +1,75 @@
"use strict";
const plugins = require("./cert.plugins");
/**
* class ChallengeHandler handles challenges
*/
class ChallengeHandler {
constructor(optionsArg) {
this._cfInstance = new plugins.cflare.CflareAccount();
this._cfInstance.auth({
email: optionsArg.cfEmail,
key: optionsArg.cfKey
});
}
/**
* set a challenge
*/
setChallenge(domainNameArg, challengeArg) {
let done = plugins.q.defer();
plugins.beautylog.log('setting challenge for ' + domainNameArg);
this._cfInstance.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;
}
/**
* cleans a challenge
*/
cleanChallenge(domainNameArg) {
let done = plugins.q.defer();
plugins.beautylog.log('cleaning challenge for ' + domainNameArg);
this._cfInstance.removeRecord(prefixName(domainNameArg), 'TXT');
cooldown().then(() => {
done.resolve();
});
return done.promise;
}
}
exports.ChallengeHandler = ChallengeHandler;
/**
* cooldown timer for letting DNS settle before answering the challengerequest
*/
let cooldown = () => {
let done = plugins.q.defer();
let cooldowntime = 60000;
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;
};
/**
* prefix a domain name to make sure it complies with letsencrypt
*/
let prefixName = (domainNameArg) => {
return '_acme-challenge.' + domainNameArg;
};
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2VydC5jbGFzc2VzLmNoYWxsZW5nZWhhbmRsZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9jZXJ0LmNsYXNzZXMuY2hhbGxlbmdlaGFuZGxlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUEsMENBQXlDO0FBUXpDOztHQUVHO0FBQ0g7SUFFSSxZQUFZLFVBQStDO1FBQ3ZELElBQUksQ0FBQyxXQUFXLEdBQUcsSUFBSSxPQUFPLENBQUMsTUFBTSxDQUFDLGFBQWEsRUFBRSxDQUFBO1FBQ3JELElBQUksQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDO1lBQ2xCLEtBQUssRUFBRSxVQUFVLENBQUMsT0FBTztZQUN6QixHQUFHLEVBQUUsVUFBVSxDQUFDLEtBQUs7U0FDeEIsQ0FBQyxDQUFBO0lBQ04sQ0FBQztJQUVEOztPQUVHO0lBQ0gsWUFBWSxDQUFDLGFBQXFCLEVBQUUsWUFBb0I7UUFDcEQsSUFBSSxJQUFJLEdBQUcsT0FBTyxDQUFDLENBQUMsQ0FBQyxLQUFLLEVBQUUsQ0FBQTtRQUM1QixPQUFPLENBQUMsU0FBUyxDQUFDLEdBQUcsQ0FBQyx3QkFBd0IsR0FBRyxhQUFhLENBQUMsQ0FBQTtRQUMvRCxJQUFJLENBQUMsV0FBVyxDQUFDLFlBQVksQ0FBQyxVQUFVLENBQUMsYUFBYSxDQUFDLEVBQUUsS0FBSyxFQUFFLFlBQVksQ0FBQyxDQUFDLElBQUksQ0FBQztZQUMvRSxPQUFPLENBQUMsU0FBUyxDQUFDLEVBQUUsQ0FBQyx5QkFBeUIsQ0FBQyxDQUFBO1lBQy9DLE9BQU8sQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLDhEQUE4RCxDQUFDLENBQUE7WUFDdEYsUUFBUSxFQUFFLENBQUMsSUFBSSxDQUFDO2dCQUNaLElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQTtZQUNsQixDQUFDLENBQUMsQ0FBQTtRQUNOLENBQUMsQ0FBQyxDQUFBO1FBQ0YsTUFBTSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUE7SUFDdkIsQ0FBQztJQUVEOztPQUVHO0lBQ0gsY0FBYyxDQUFDLGFBQWE7UUFDeEIsSUFBSSxJQUFJLEdBQUcsT0FBTyxDQUFDLENBQUMsQ0FBQyxLQUFLLEVBQUUsQ0FBQTtRQUM1QixPQUFPLENBQUMsU0FBUyxDQUFDLEdBQUcsQ0FBQyx5QkFBeUIsR0FBRyxhQUFhLENBQUMsQ0FBQTtRQUNoRSxJQUFJLENBQUMsV0FBVyxDQUFDLFlBQVksQ0FBQyxVQUFVLENBQUMsYUFBYSxDQUFDLEVBQUUsS0FBSyxDQUFDLENBQUE7UUFDL0QsUUFBUSxFQUFFLENBQUMsSUFBSSxDQUFDO1lBQ1osSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFBO1FBQ2xCLENBQUMsQ0FBQyxDQUFBO1FBQ0YsTUFBTSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUE7SUFDdkIsQ0FBQztDQUNKO0FBdENELDRDQXNDQztBQUVEOztHQUVHO0FBQ0gsSUFBSSxRQUFRLEdBQUc7SUFDWCxJQUFJLElBQUksR0FBRyxPQUFPLENBQUMsQ0FBQyxDQUFDLEtBQUssRUFBRSxDQUFBO0lBQzVCLElBQUksWUFBWSxHQUFHLEtBQUssQ0FBQTtJQUN4QixJQUFJLFVBQVUsR0FBRyxDQUFDLENBQUE7SUFDbEIsT0FBTyxDQUFDLFNBQVMsQ0FBQyxHQUFHLENBQUMsZ0JBQWdCLEdBQUcsQ0FBQyxZQUFZLEdBQUcsSUFBSSxDQUFDLENBQUMsUUFBUSxFQUFFLEdBQUcsZUFBZSxDQUFDLENBQUE7SUFDNUYsSUFBSSxlQUFlLEdBQUc7UUFDbEIsVUFBVSxDQUFDO1lBQ1AsRUFBRSxDQUFDLENBQUMsWUFBWSxJQUFJLFVBQVUsQ0FBQyxDQUFDLENBQUM7Z0JBQzdCLE9BQU8sQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDLGNBQWMsQ0FBQyxDQUFBO2dCQUNwQyxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUE7WUFDbEIsQ0FBQztZQUFDLElBQUksQ0FBQyxDQUFDO2dCQUNKLFVBQVUsR0FBRyxVQUFVLEdBQUcsSUFBSSxDQUFBO2dCQUM5QixPQUFPLENBQUMsU0FBUyxDQUFDLEdBQUcsQ0FBQyxnQkFBZ0I7c0JBQ2hDLENBQUMsQ0FBQyxZQUFZLEdBQUcsVUFBVSxDQUFDLEdBQUcsSUFBSSxDQUFDLENBQUMsUUFBUSxFQUFFO3NCQUMvQyxlQUFlLENBQ3BCLENBQUE7Z0JBQ0QsZUFBZSxFQUFFLENBQUE7WUFDckIsQ0FBQztRQUNMLENBQUMsRUFBRSxJQUFJLENBQUMsQ0FBQTtJQUNaLENBQUMsQ0FBQTtJQUNELGVBQWUsRUFBRSxDQUFBO0lBQ2pCLE1BQU0sQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFBO0FBQ3ZCLENBQUMsQ0FBQTtBQUVEOztHQUVHO0FBQ0gsSUFBSSxVQUFVLEdBQUcsQ0FBQyxhQUFxQjtJQUNuQyxNQUFNLENBQUMsa0JBQWtCLEdBQUcsYUFBYSxDQUFBO0FBQzdDLENBQUMsQ0FBQSJ9

26
dist/cert.classes.letsencrypt.d.ts vendored Normal file
View File

@ -0,0 +1,26 @@
/// <reference types="q" />
import * as q from 'q';
import { ChallengeHandler } from './cert.classes.challengehandler';
export declare type TLeEnv = 'production' | 'staging';
export interface ILetsencryptConstructorOptions {
leEnv: TLeEnv;
challengeHandler: ChallengeHandler;
sslDir: string;
}
export declare class Letsencrypt {
leEnv: TLeEnv;
challengeHandler: ChallengeHandler;
sslDir: string;
private _leInstance;
private _leServerUrl;
constructor(optionsArg: ILetsencryptConstructorOptions);
/**
* register a domain
*/
registerDomain(domainNameArg: string): q.Promise<{}>;
private _leCopyToDestination(domainNameArg);
/**
* translates to the format expected by letsencrypt node implementation
*/
private _leChallengeHandler();
}

136
dist/cert.classes.letsencrypt.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -1,5 +0,0 @@
/// <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
View File

@ -1,25 +0,0 @@
"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

0
dist/cert.hook.d.ts vendored
View File

65
dist/cert.hook.js vendored
View File

@ -1,65 +0,0 @@
#!/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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2VydC5ob29rLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvY2VydC5ob29rLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBR0EsTUFBWSxPQUFPLFdBQU0sZ0JBQWdCLENBQUMsQ0FBQTtBQUMxQyxNQUFZLEtBQUssV0FBTSxjQUFjLENBQUMsQ0FBQTtBQUV0QyxJQUFJLFFBQVEsR0FBRyxJQUFJLE9BQU8sQ0FBQyxRQUFRLENBQUMsUUFBUSxFQUFFLENBQUM7QUFFL0MsSUFBSSxNQUFNLEdBQUcsT0FBTyxDQUFDLFNBQVMsQ0FBQyxFQUFFLENBQUMsWUFBWSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQztBQUM3RCxJQUFJLE1BQU0sR0FBRyxJQUFJLE9BQU8sQ0FBQyxNQUFNLENBQUMsYUFBYSxFQUFFLENBQUM7QUFDaEQsTUFBTSxDQUFDLElBQUksQ0FBQztJQUNSLEtBQUssRUFBRSxNQUFNLENBQUMsT0FBTztJQUNyQixHQUFHLEVBQUUsTUFBTSxDQUFDLEtBQUs7Q0FDcEIsQ0FBQyxDQUFDO0FBRUgsSUFBSSxZQUFZLEdBQUcsQ0FBQyxhQUFxQixFQUFFLFlBQW9CO0lBQzNELElBQUksSUFBSSxHQUFHLE9BQU8sQ0FBQyxDQUFDLENBQUMsS0FBSyxFQUFFLENBQUM7SUFDN0IsT0FBTyxDQUFDLFNBQVMsQ0FBQyxHQUFHLENBQUMsd0JBQXdCLEdBQUcsYUFBYSxDQUFDLENBQUM7SUFDaEUsTUFBTSxDQUFDLFlBQVksQ0FBQyxVQUFVLENBQUMsYUFBYSxDQUFDLEVBQUUsS0FBSyxFQUFFLFlBQVksQ0FBQyxDQUFDLElBQUksQ0FBQztRQUNyRSxPQUFPLENBQUMsU0FBUyxDQUFDLEVBQUUsQ0FBQyx5QkFBeUIsQ0FBQyxDQUFDO1FBQ2hELE9BQU8sQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLDhEQUE4RCxDQUFDLENBQUM7UUFDdkYsUUFBUSxFQUFFLENBQUMsSUFBSSxDQUFDO1lBQ1osSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDO1FBQ25CLENBQUMsQ0FBQyxDQUFDO0lBQ1AsQ0FBQyxDQUFDLENBQUM7SUFDSCxNQUFNLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQztBQUN4QixDQUFDLENBQUE7QUFFRCxJQUFJLGNBQWMsR0FBRyxDQUFDLGFBQWE7SUFDL0IsSUFBSSxJQUFJLEdBQUcsT0FBTyxDQUFDLENBQUMsQ0FBQyxLQUFLLEVBQUUsQ0FBQztJQUM3QixPQUFPLENBQUMsU0FBUyxDQUFDLEdBQUcsQ0FBQyx5QkFBeUIsR0FBRyxhQUFhLENBQUMsQ0FBQztJQUNqRSxNQUFNLENBQUMsWUFBWSxDQUFDLFVBQVUsQ0FBQyxhQUFhLENBQUMsRUFBRSxLQUFLLENBQUMsQ0FBQztJQUN0RCxNQUFNLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQztBQUN4QixDQUFDLENBQUE7QUFFRCxJQUFJLFFBQVEsR0FBRztJQUNYLElBQUksSUFBSSxHQUFHLE9BQU8sQ0FBQyxDQUFDLENBQUMsS0FBSyxFQUFFLENBQUM7SUFDN0IsSUFBSSxZQUFZLEdBQUcsTUFBTSxDQUFDO0lBQzFCLElBQUksVUFBVSxHQUFHLENBQUMsQ0FBQztJQUNuQixPQUFPLENBQUMsU0FBUyxDQUFDLEdBQUcsQ0FBQyxnQkFBZ0IsR0FBRyxDQUFDLFlBQVksR0FBQyxJQUFJLENBQUMsQ0FBQyxRQUFRLEVBQUUsR0FBRyxlQUFlLENBQUMsQ0FBQztJQUMzRixJQUFJLGVBQWUsR0FBRztRQUNsQixVQUFVLENBQUM7WUFDUCxFQUFFLENBQUEsQ0FBQyxZQUFZLElBQUksVUFBVSxDQUFDLENBQUEsQ0FBQztnQkFDM0IsT0FBTyxDQUFDLFNBQVMsQ0FBQyxFQUFFLENBQUMsY0FBYyxDQUFDLENBQUM7Z0JBQ3JDLElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQztZQUNuQixDQUFDO1lBQUMsSUFBSSxDQUFDLENBQUM7Z0JBQ0osVUFBVSxHQUFHLFVBQVUsR0FBRyxJQUFJLENBQUM7Z0JBQy9CLE9BQU8sQ0FBQyxTQUFTLENBQUMsR0FBRyxDQUFDLGdCQUFnQixHQUFHLENBQUMsQ0FBQyxZQUFZLEdBQUcsVUFBVSxDQUFDLEdBQUMsSUFBSSxDQUFDLENBQUMsUUFBUSxFQUFFLEdBQUcsZUFBZSxDQUFDLENBQUM7Z0JBQzFHLGVBQWUsRUFBRSxDQUFDO1lBQ3RCLENBQUM7UUFDTCxDQUFDLEVBQUUsSUFBSSxDQUFDLENBQUM7SUFDYixDQUFDLENBQUE7SUFDRCxlQUFlLEVBQUUsQ0FBQztJQUNsQixNQUFNLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQztBQUN4QixDQUFDLENBQUE7QUFFRCxJQUFJLFVBQVUsR0FBRyxDQUFDLGFBQXFCO0lBQ25DLE1BQU0sQ0FBQyxrQkFBa0IsR0FBRyxhQUFhLENBQUM7QUFDOUMsQ0FBQyxDQUFBO0FBRUQsUUFBUSxDQUFDLFVBQVUsQ0FBQztJQUNoQixXQUFXLEVBQUUsa0JBQWtCO0NBQ2xDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxJQUFJO0lBQ1QsWUFBWSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0FBQ3ZDLENBQUMsQ0FBQyxDQUFDO0FBRUgsUUFBUSxDQUFDLFVBQVUsQ0FBQztJQUNoQixXQUFXLEVBQUUsaUJBQWlCO0NBQ2pDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxJQUFJO0lBQ1QsY0FBYyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztBQUM5QixDQUFDLENBQUMsQ0FBQztBQUVILFFBQVEsQ0FBQyxVQUFVLEVBQUUsQ0FBQyJ9

10
dist/cert.paths.d.ts vendored
View File

@ -1,8 +1,4 @@
export declare let certDir: string;
export declare let defaultSslDir: string;
export declare let projectDir: 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;
export declare let defaultSslDir: string;
export declare let leConfigDir: string;

19
dist/cert.paths.js vendored
View File

@ -1,13 +1,10 @@
"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=
// dirs
exports.projectDir = plugins.path.join(__dirname, '../');
exports.assetDir = plugins.path.join(exports.projectDir, 'assets');
exports.defaultSslDir = plugins.path.join(exports.assetDir, 'defaultSslDir');
exports.leConfigDir = plugins.path.join(exports.assetDir, 'letsencrypt');
plugins.smartfile.fs.ensureDirSync(exports.leConfigDir);
plugins.smartfile.fs.ensureDirSync(exports.defaultSslDir);
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2VydC5wYXRocy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL2NlcnQucGF0aHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLDBDQUF5QztBQUV6QyxPQUFPO0FBQ0ksUUFBQSxVQUFVLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFDLEtBQUssQ0FBQyxDQUFBO0FBQy9DLFFBQUEsUUFBUSxHQUFHLE9BQU8sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLGtCQUFVLEVBQUMsUUFBUSxDQUFDLENBQUE7QUFDakQsUUFBQSxhQUFhLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsZ0JBQVEsRUFBQyxlQUFlLENBQUMsQ0FBQTtBQUMzRCxRQUFBLFdBQVcsR0FBRyxPQUFPLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxnQkFBUSxFQUFDLGFBQWEsQ0FBQyxDQUFBO0FBQ2xFLE9BQU8sQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDLGFBQWEsQ0FBQyxtQkFBVyxDQUFDLENBQUE7QUFDL0MsT0FBTyxDQUFDLFNBQVMsQ0FBQyxFQUFFLENBQUMsYUFBYSxDQUFDLHFCQUFhLENBQUMsQ0FBQSJ9

View File

@ -1,12 +1,13 @@
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");
import 'typings-global';
import * as beautylog from 'beautylog';
import * as cflare from 'cflare';
declare let fs: any;
import * as lik from 'lik';
import * as path from 'path';
import * as q from 'q';
import * as shelljs from 'shelljs';
import * as smartcli from 'smartcli';
import * as smartfile from 'smartfile';
import * as smartgit from 'smartgit';
import * as smartstring from 'smartstring';
export { beautylog, cflare, fs, lik, path, q, shelljs, smartcli, smartfile, smartgit, smartstring };

35
dist/cert.plugins.js vendored
View File

@ -1,14 +1,25 @@
"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=
const beautylog = require("beautylog");
exports.beautylog = beautylog;
const cflare = require("cflare");
exports.cflare = cflare;
let fs = require('fs-extra');
exports.fs = fs;
const lik = require("lik");
exports.lik = lik;
const path = require("path");
exports.path = path;
const q = require("q");
exports.q = q;
const shelljs = require("shelljs");
exports.shelljs = shelljs;
const smartcli = require("smartcli");
exports.smartcli = smartcli;
const smartfile = require("smartfile");
exports.smartfile = smartfile;
const smartgit = require("smartgit");
exports.smartgit = smartgit;
const smartstring = require("smartstring");
exports.smartstring = smartstring;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2VydC5wbHVnaW5zLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvY2VydC5wbHVnaW5zLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQSwwQkFBdUI7QUFDdkIsdUNBQXNDO0FBYWxDLDhCQUFTO0FBWmIsaUNBQWdDO0FBYTVCLHdCQUFNO0FBWlYsSUFBSSxFQUFFLEdBQUcsT0FBTyxDQUFDLFVBQVUsQ0FBQyxDQUFBO0FBYXhCLGdCQUFFO0FBWk4sMkJBQTBCO0FBYXRCLGtCQUFHO0FBWlAsNkJBQTRCO0FBYXhCLG9CQUFJO0FBWlIsdUJBQXNCO0FBYWxCLGNBQUM7QUFaTCxtQ0FBa0M7QUFhOUIsMEJBQU87QUFaWCxxQ0FBb0M7QUFhaEMsNEJBQVE7QUFaWix1Q0FBc0M7QUFhbEMsOEJBQVM7QUFaYixxQ0FBb0M7QUFhaEMsNEJBQVE7QUFaWiwyQ0FBMEM7QUFhdEMsa0NBQVcifQ==

45
dist/index.d.ts vendored
View File

@ -1,44 +1 @@
/// <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();
}
export * from './cert.classes.cert';

161
dist/index.js vendored

File diff suppressed because one or more lines are too long

3
dist/install.d.ts vendored
View File

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

19
dist/install.js vendored
View File

@ -1,19 +0,0 @@
"use strict";
const plugins = require("./cert.plugins");
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==

5
npmextra.json Normal file
View File

@ -0,0 +1,5 @@
{
"npmts": {
"mode": "default"
}
}

View File

@ -1,13 +1,12 @@
{
"name": "cert",
"version": "1.0.3",
"version": "1.0.8",
"description": "Easily obain SSL certificates from LetsEncrypt. Supports DNS-01 challenge. TypeScript ready.",
"main": "dist/index.js",
"typings": "dist/index.d.ts",
"scripts": {
"test": "(npm run cleanTest && npmts)",
"test": "(npm run cleanTest && npmts --nodocs)",
"cleanTest": "(rm -rf ./test/assets)",
"install": "node dist/install.js install",
"compile": "(npmts --notest)"
},
"repository": {
@ -27,25 +26,25 @@
},
"homepage": "https://gitlab.com/pushrocks/cert#readme",
"dependencies": {
"@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",
"@types/minimatch": "2.x.x",
"@types/q": "0.0.32",
"beautylog": "^6.0.0",
"cflare": "0.0.10",
"fs-extra": "^1.0.0",
"lik": "^1.0.27",
"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"
"smartacme": "^1.0.2",
"smartcli": "^2.0.1",
"smartfile": "^4.1.1",
"smartgit": "1.0.5",
"smartstring": "^2.0.22",
"typings-global": "^1.0.14"
},
"devDependencies": {
"npmts-g": "^5.2.6",
"qenv": "^1.0.8",
"should": "^10.0.0",
"typings-test": "^1.0.1"
"@types/should": "^8.1.30",
"npmts-g": "^5.2.10",
"qenv": "^1.1.1",
"should": "^11.1.2",
"typings-test": "^1.0.3"
}
}

1656
pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load Diff

3
test/test.d.ts vendored
View File

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

View File

@ -1,47 +1,43 @@
"use strict";
require("typings-test");
require("should");
const should = 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 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);
describe('cert', function () {
describe('Cert', function () {
it('should create a new Cert object from class', function () {
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
sslDirPath: path.join(process.cwd(), 'test/assets'),
gitOriginRepo: 'git@gitlab.com:sandboxzone/sandbox-sslorigin.git',
leEnv: 'staging'
});
testCert.should.be.instanceof(cert.Cert);
should(testCert).be.instanceof(cert.Cert);
});
it("should get a valid certificate", function (done) {
this.timeout(400000);
it('should run class Cert.setup() successful', function (done) {
this.timeout(40000);
testCert.setup().then(() => {
done();
});
});
it('should get a valid certificate', function (done) {
this.timeout(1200000);
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`));
promiseArray.push(testCert.addCertificate(`testing${getRandomArbitrary(1, 100000)}.bleu.de`));
// promiseArray.push(testCert.addCertificate(`testing${getRandomArbitrary(1,100000)}.bleu.de`))
// promiseArray.push(testCert.addCertificate(`testing${getRandomArbitrary(1,100000)}.bleu.de`))
q.all(promiseArray).then(() => {
done();
});
});
});
});
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGVzdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbInRlc3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLFFBQU8sY0FBYyxDQUFDLENBQUE7QUFDdEIsUUFBTyxRQUFRLENBQUMsQ0FBQTtBQUNoQix1QkFBbUIsTUFBTSxDQUFDLENBQUE7QUFDMUIsTUFBTyxJQUFJLFdBQVcsTUFBTSxDQUFDLENBQUM7QUFDOUIsTUFBTyxDQUFDLFdBQVcsR0FBRyxDQUFDLENBQUM7QUFDeEIsMEJBQTJCLGlCQUFpQixDQUFDLENBQUE7QUFDN0MsTUFBWSxJQUFJLFdBQU0sZUFBZSxDQUFDLENBQUE7QUFHdEMsSUFBSSxRQUFRLEdBQUcsSUFBSSxXQUFJLENBQUMsT0FBTyxDQUFDLEdBQUcsRUFBRSxFQUFFLE9BQU8sQ0FBQyxHQUFHLEVBQUUsR0FBRyxTQUFTLENBQUMsQ0FBQztBQUVsRSxJQUFJLFFBQWtCLENBQUM7QUFFdkIsUUFBUSxDQUFDLE1BQU0sRUFBQztJQUNaLFFBQVEsQ0FBQyxTQUFTLEVBQUM7UUFDZixFQUFFLENBQUMsZ0NBQWdDLEVBQUMsVUFBUyxJQUFJO1lBQzdDLElBQUksQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUM7WUFDbkIsc0JBQVksRUFBRSxDQUFDLElBQUksQ0FBQztnQkFDaEIsSUFBSSxFQUFFLENBQUM7WUFDWCxDQUFDLENBQUMsQ0FBQTtRQUNOLENBQUMsQ0FBQyxDQUFBO0lBQ04sQ0FBQyxDQUFDLENBQUE7SUFDRixRQUFRLENBQUMsTUFBTSxFQUFDO1FBQ1osRUFBRSxDQUFDLDRDQUE0QyxFQUFDO1lBQzVDLElBQUksQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUM7WUFDcEIsUUFBUSxHQUFHLElBQUksSUFBSSxDQUFDLElBQUksQ0FBQztnQkFDckIsT0FBTyxFQUFFLE9BQU8sQ0FBQyxHQUFHLENBQUMsUUFBUTtnQkFDN0IsS0FBSyxFQUFFLE9BQU8sQ0FBQyxHQUFHLENBQUMsTUFBTTtnQkFDekIsTUFBTSxFQUFFLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLEdBQUcsRUFBRSxFQUFDLGFBQWEsQ0FBQztnQkFDOUMsYUFBYSxFQUFDLGtEQUFrRDtnQkFDaEUsUUFBUSxFQUFDLElBQUk7YUFDaEIsQ0FBQyxDQUFDO1lBQ0gsUUFBUSxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUM3QyxDQUFDLENBQUMsQ0FBQTtRQUNGLEVBQUUsQ0FBQyxnQ0FBZ0MsRUFBQyxVQUFTLElBQUk7WUFDN0MsSUFBSSxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsQ0FBQztZQUNyQixJQUFJLFlBQVksR0FBRyxFQUFFLENBQUM7WUFDdEIsNEJBQTRCLEdBQUcsRUFBRSxHQUFHO2dCQUNoQyxNQUFNLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLEdBQUcsQ0FBQyxHQUFHLEdBQUcsR0FBRyxDQUFDLEdBQUcsR0FBRyxDQUFDLENBQUM7WUFDekQsQ0FBQztZQUNELFlBQVksQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLGFBQWEsQ0FBQyxVQUFVLGtCQUFrQixDQUFDLENBQUMsRUFBQyxNQUFNLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQztZQUM1Riw4RkFBOEY7WUFDOUYsOEZBQThGO1lBQzlGLENBQUMsQ0FBQyxHQUFHLENBQUMsWUFBWSxDQUFDLENBQUMsSUFBSSxDQUFDO2dCQUNyQixJQUFJLEVBQUUsQ0FBQztZQUNYLENBQUMsQ0FBQyxDQUFDO1FBQ1AsQ0FBQyxDQUFDLENBQUE7SUFDTixDQUFDLENBQUMsQ0FBQTtBQUNOLENBQUMsQ0FBQyxDQUFDIn0=
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGVzdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbInRlc3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLHdCQUFxQjtBQUNyQixpQ0FBZ0M7QUFDaEMsK0JBQXlCO0FBQ3pCLDZCQUE2QjtBQUM3Qix1QkFBdUI7QUFDdkIsc0NBQXFDO0FBR3JDLElBQUksUUFBUSxHQUFHLElBQUksV0FBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLEVBQUUsRUFBRSxPQUFPLENBQUMsR0FBRyxFQUFFLEdBQUcsU0FBUyxDQUFDLENBQUE7QUFFakUsSUFBSSxRQUFtQixDQUFBO0FBRXZCLFFBQVEsQ0FBQyxNQUFNLEVBQUM7SUFDWixRQUFRLENBQUMsTUFBTSxFQUFDO1FBQ1osRUFBRSxDQUFDLDRDQUE0QyxFQUFDO1lBQzVDLFFBQVEsR0FBRyxJQUFJLElBQUksQ0FBQyxJQUFJLENBQUM7Z0JBQ3JCLE9BQU8sRUFBRSxPQUFPLENBQUMsR0FBRyxDQUFDLFFBQVE7Z0JBQzdCLEtBQUssRUFBRSxPQUFPLENBQUMsR0FBRyxDQUFDLE1BQU07Z0JBQ3pCLFVBQVUsRUFBRSxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLEVBQUUsRUFBQyxhQUFhLENBQUM7Z0JBQ2xELGFBQWEsRUFBRSxrREFBa0Q7Z0JBQ2pFLEtBQUssRUFBRSxTQUFTO2FBQ25CLENBQUMsQ0FBQTtZQUNGLE1BQU0sQ0FBQyxRQUFRLENBQUMsQ0FBQyxFQUFFLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQTtRQUM3QyxDQUFDLENBQUMsQ0FBQTtRQUNGLEVBQUUsQ0FBQywwQ0FBMEMsRUFBRSxVQUFTLElBQUk7WUFDeEQsSUFBSSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsQ0FBQTtZQUNuQixRQUFRLENBQUMsS0FBSyxFQUFFLENBQUMsSUFBSSxDQUFDO2dCQUNsQixJQUFJLEVBQUUsQ0FBQTtZQUNWLENBQUMsQ0FBQyxDQUFBO1FBQ04sQ0FBQyxDQUFDLENBQUE7UUFDRixFQUFFLENBQUMsZ0NBQWdDLEVBQUMsVUFBUyxJQUFJO1lBQzdDLElBQUksQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLENBQUE7WUFDckIsSUFBSSxZQUFZLEdBQUcsRUFBRSxDQUFBO1lBQ3JCLDRCQUE0QixHQUFHLEVBQUUsR0FBRztnQkFDaEMsTUFBTSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRSxHQUFHLENBQUMsR0FBRyxHQUFHLEdBQUcsQ0FBQyxHQUFHLEdBQUcsQ0FBQyxDQUFBO1lBQ3hELENBQUM7WUFDRCxZQUFZLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxjQUFjLENBQUMsVUFBVSxrQkFBa0IsQ0FBQyxDQUFDLEVBQUMsTUFBTSxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUE7WUFDNUYsK0ZBQStGO1lBQy9GLCtGQUErRjtZQUMvRixDQUFDLENBQUMsR0FBRyxDQUFDLFlBQVksQ0FBQyxDQUFDLElBQUksQ0FBQztnQkFDckIsSUFBSSxFQUFFLENBQUE7WUFDVixDQUFDLENBQUMsQ0FBQTtRQUNOLENBQUMsQ0FBQyxDQUFBO0lBQ04sQ0FBQyxDQUFDLENBQUE7QUFDTixDQUFDLENBQUMsQ0FBQSJ9

View File

@ -1,49 +1,45 @@
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";
import 'typings-test'
import * as should from 'should'
import {Qenv} from 'qenv'
import path = require('path')
import q = require('q')
import * as cert from '../dist/index'
let testQenv = new Qenv(process.cwd(), process.cwd() + "/.nogit");
let testQenv = new Qenv(process.cwd(), process.cwd() + '/.nogit')
let testCert:cert.Cert;
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);
describe('cert',function(){
describe('Cert',function(){
it('should create a new Cert object from class',function(){
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);
sslDirPath: path.join(process.cwd(),'test/assets'),
gitOriginRepo: 'git@gitlab.com:sandboxzone/sandbox-sslorigin.git',
leEnv: 'staging'
})
should(testCert).be.instanceof(cert.Cert)
})
it("should get a valid certificate",function(done){
this.timeout(400000);
let promiseArray = [];
it('should run class Cert.setup() successful', function(done){
this.timeout(40000)
testCert.setup().then(() => {
done()
})
})
it('should get a valid certificate',function(done){
this.timeout(1200000)
let promiseArray = []
function getRandomArbitrary(min, max) {
return Math.floor(Math.random() * (max - min) + min);
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`));
promiseArray.push(testCert.addCertificate(`testing${getRandomArbitrary(1,100000)}.bleu.de`))
// promiseArray.push(testCert.addCertificate(`testing${getRandomArbitrary(1,100000)}.bleu.de`))
// promiseArray.push(testCert.addCertificate(`testing${getRandomArbitrary(1,100000)}.bleu.de`))
q.all(promiseArray).then(() => {
done();
});
done()
})
})
})
});
})

98
ts/cert.classes.cert.ts Normal file
View File

@ -0,0 +1,98 @@
import * as q from 'q'
import { Stringmap, Objectmap } from 'lik'
import * as plugins from './cert.plugins'
import * as paths from './cert.paths'
// classes
import { Certificate } from './cert.classes.certificate'
import { CertRepo } from './cert.classes.certrepo'
import { Letsencrypt, TLeEnv } from './cert.classes.letsencrypt'
import { ChallengeHandler } from './cert.classes.challengehandler'
export interface ICertConstructorOptions {
cfEmail: string,
cfKey: string,
sslDirPath?: string,
gitOriginRepo?: string,
leEnv?: TLeEnv
}
export class Cert {
domainStringRequestMap = new Stringmap()
certificateMap = new Objectmap<Certificate>()
letsencrypt: Letsencrypt
private _challengeHandler: ChallengeHandler
private _certRepo: CertRepo
/**
* Constructor for Cert object
*/
constructor(optionsArg: ICertConstructorOptions) {
// set up challengehandler
this._challengeHandler = new ChallengeHandler({
cfEmail: optionsArg.cfEmail,
cfKey: optionsArg.cfKey
})
// setup Letsencrypt
this.letsencrypt = new Letsencrypt({
leEnv: optionsArg.leEnv,
sslDir: optionsArg.sslDirPath,
challengeHandler: this._challengeHandler
})
this._certRepo = new CertRepo({
sslDirPath: optionsArg.sslDirPath,
remoteGitUrl: optionsArg.gitOriginRepo,
certInstance: this
})
}
/**
* setup the Cert instanceof
* @executes ASYNC
* @return Promise
*/
setup() {
return this._certRepo.setup()
}
/**
* adds a Certificate for a given domain
*/
addCertificate(domainNameArg: string, optionsArg: { force: boolean } = { force: false }) {
let done = q.defer()
let certificateForDomain = this.certificateMap.find((certificate) => {
return certificate.domainName === domainNameArg
})
if (certificateForDomain instanceof Certificate) {
certificateForDomain.renew()
.then(done.resolve)
} else {
certificateForDomain = new Certificate({
certInstance: this,
domainName: domainNameArg
})
certificateForDomain.renew()
.then(done.resolve)
}
return done.promise
}
/**
* cleans up old certificates
*/
cleanOldCertificates() {
}
/**
* executes the current batch of jobs
*/
deploy() {
}
}

View File

@ -0,0 +1,129 @@
import * as q from 'q'
import * as plugins from './cert.plugins'
import * as paths from './cert.paths'
// import classes
import { Cert } from './cert.classes.cert'
import { Letsencrypt } from './cert.classes.letsencrypt'
import { CertRepo } from './cert.classes.certrepo'
export interface ICertificateFsConfig {
domainName: string
creationTime: number
expiryTime: number
}
export interface ICertificateConstructorOptions {
domainName: string,
certInstance: Cert
}
export type TCertificateStatus = 'unregistered' | 'valid' | 'expiring' | 'expired'
export class Certificate {
domainName: string
certInstance: Cert
domainData: plugins.smartstring.Domain
creationDate: Date = null
expiryDate: Date = null
publicKey: string = null
privKey: string = null
/**
* run when creating a new instance of Certificate
*/
constructor(optionsArg: ICertificateConstructorOptions) {
this.domainName = optionsArg.domainName
this.domainData = new plugins.smartstring.Domain(this.domainName)
this.certInstance = optionsArg.certInstance
}
/**
* the status of the Certificate
*/
get status(): TCertificateStatus {
let validTimeRemaining: number = 0
if (this.creationDate !== null && this.expiryDate !== null) {
validTimeRemaining = this.expiryDate.getTime() - Date.now()
}
let MonthMilliseconds = 2629746000
if (this.publicKey === null || this.privKey === null) {
return 'unregistered'
} else if (validTimeRemaining >= MonthMilliseconds) {
return 'valid'
} else if (validTimeRemaining < MonthMilliseconds && validTimeRemaining >= 0) {
return 'expiring'
} else {
return 'expired'
}
}
get sameZoneRequesting(): boolean {
return this.certInstance.domainStringRequestMap.checkMinimatch('*' + this.domainData.zoneName)
}
/**
* schedule a retry of certificate request
*/
scheduleRetry() {
let done = plugins.q.defer()
setTimeout(() => {
this.renew()
.then(done.resolve)
}, 60000)
return done.promise
}
/**
* renew certificate if needed
*/
renew(force: boolean = false) {
let done = q.defer()
if (this.status === 'valid') {
plugins.beautylog.log('Certificate still valid for more than 1 month, so it is not renewed now')
done.resolve()
} else if (this.status === 'expiring' || this.status === 'expired' || this.status === 'unregistered') {
plugins.beautylog.info('Certificate not valid currently, going to renew now!')
if (this.sameZoneRequesting) {
this.certInstance.domainStringRequestMap.registerUntilTrue(
() => {
return !this.sameZoneRequesting
},
() => {
this.renew().then(done.resolve)
}
)
} else {
this.certInstance.letsencrypt.registerDomain(this.domainName)
.then(() => {
return this.syncFs()
})
.then(() => {
done.resolve()
}).catch((err) => { console.log(err) })
}
} else {
throw Error(`weird status for certificate with domain name ${this.domainName}`)
}
done.resolve()
return done.promise
}
/**
* syncFs syncs the certificate with disk
*/
syncFs() {
let configJsonMemory: ICertificateFsConfig = {
domainName: this.domainName,
creationTime: this.creationDate.getTime(),
expiryTime: this.expiryDate.getTime()
}
}
/**
* deletes the certificate
*/
delete() { }
}

View File

@ -0,0 +1,77 @@
import * as q from 'q'
import { GitRepo } from 'smartgit'
import * as plugins from './cert.plugins'
import * as paths from './cert.paths'
import { Cert } from './cert.classes.cert'
import { Certificate } from './cert.classes.certificate'
export interface ICertRepoConstructorOptions {
sslDirPath: string
remoteGitUrl: string
certInstance: Cert
}
export class CertRepo {
private _sslDirPath: string
private _remoteGitUrl: string
private gitRepo: GitRepo
private _certInstance: Cert
constructor(optionsArg: ICertRepoConstructorOptions) {
this._sslDirPath = optionsArg.sslDirPath
this._remoteGitUrl = optionsArg.remoteGitUrl
this._certInstance = optionsArg.certInstance
// setup sslDir
if (!this._sslDirPath) {
this._sslDirPath = paths.defaultSslDir
}
}
/**
* setup the Cert instance
*/
setup() {
// setup Git
let done = q.defer()
if (this._remoteGitUrl) {
plugins.smartfile.fs.ensureEmptyDirSync(paths.defaultSslDir)
plugins.smartgit.createRepoFromClone(this._remoteGitUrl, paths.defaultSslDir)
.then(gitRepoArg => {
this.gitRepo = gitRepoArg
done.resolve()
})
}
return done.promise
}
/**
* syncs an objectmap of Certificates with repo
*/
syncFs() {
let done = q.defer()
done.resolve()
return done.promise
}
/**
* Pulls already requested certificates from git origin
*/
sslGitOriginPull = () => {
if (this.gitRepo) {
this.gitRepo.pull('origin', 'master')
}
}
/**
* Pushes all new requested certificates to git origin
*/
sslGitOriginAddCommitPush = () => {
if (this._remoteGitUrl) {
this.gitRepo.addAll()
this.gitRepo.commit('added new SSL certificates and deleted obsolete ones.')
this.gitRepo.push('origin', 'master')
}
}
}

View File

@ -0,0 +1,84 @@
import * as plugins from './cert.plugins'
import * as paths from './cert.paths'
export interface IChallengehandlerConstructorOptions {
cfEmail: string,
cfKey: string,
}
/**
* class ChallengeHandler handles challenges
*/
export class ChallengeHandler {
private _cfInstance: plugins.cflare.CflareAccount
constructor(optionsArg: IChallengehandlerConstructorOptions) {
this._cfInstance = new plugins.cflare.CflareAccount()
this._cfInstance.auth({
email: optionsArg.cfEmail,
key: optionsArg.cfKey
})
}
/**
* set a challenge
*/
setChallenge(domainNameArg: string, challengeArg: string) {
let done = plugins.q.defer()
plugins.beautylog.log('setting challenge for ' + domainNameArg)
this._cfInstance.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
}
/**
* cleans a challenge
*/
cleanChallenge(domainNameArg) {
let done = plugins.q.defer()
plugins.beautylog.log('cleaning challenge for ' + domainNameArg)
this._cfInstance.removeRecord(prefixName(domainNameArg), 'TXT')
cooldown().then(() => {
done.resolve()
})
return done.promise
}
}
/**
* cooldown timer for letting DNS settle before answering the challengerequest
*/
let cooldown = () => {
let done = plugins.q.defer()
let cooldowntime = 60000
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
}
/**
* prefix a domain name to make sure it complies with letsencrypt
*/
let prefixName = (domainNameArg: string): string => {
return '_acme-challenge.' + domainNameArg
}

View File

@ -0,0 +1,48 @@
import * as q from 'q'
let letsencrypt = require('letsencrypt')
let leStore = require('le-store-certbot')
import * as plugins from './cert.plugins'
import * as paths from './cert.paths'
import { ChallengeHandler } from './cert.classes.challengehandler'
export type TLeEnv = 'production' | 'staging'
export interface ILetsencryptConstructorOptions {
leEnv: TLeEnv,
challengeHandler: ChallengeHandler,
sslDir: string
}
export class Letsencrypt {
leEnv: TLeEnv
challengeHandler: ChallengeHandler // this is the format we use
sslDir: string
private _leServerUrl: string
constructor(optionsArg: ILetsencryptConstructorOptions) {
// determine leEnv
this.leEnv = optionsArg.leEnv
this.challengeHandler = optionsArg.challengeHandler
this.sslDir = optionsArg.sslDir
// set letsencrypt environment
if (this.leEnv === 'production') {
this._leServerUrl = letsencrypt.productionServerUrl
} else if (this.leEnv === 'staging') {
this._leServerUrl = letsencrypt.stagingServerUrl
}
}
/**
* register a domain
*/
registerDomain(domainNameArg: string) {
plugins.beautylog.log(`trying to register domain ${domainNameArg}`)
let done = q.defer()
plugins.smartfile.fs.ensureDirSync(plugins.path.join(paths.leConfigDir, 'live', domainNameArg))
return done.promise
}
}

View File

@ -1,25 +0,0 @@
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;
};

View File

@ -1,73 +0,0 @@
#!/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();

View File

@ -1,14 +1,9 @@
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");
import * as plugins from './cert.plugins'
// dirs
export let projectDir = plugins.path.join(__dirname,'../')
export let assetDir = plugins.path.join(projectDir,'assets')
export let defaultSslDir = plugins.path.join(assetDir,'defaultSslDir')
export let leConfigDir = plugins.path.join(assetDir,'letsencrypt')
plugins.smartfile.fs.ensureDirSync(leConfigDir)
plugins.smartfile.fs.ensureDirSync(defaultSslDir)

View File

@ -1,13 +1,26 @@
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");
import 'typings-global'
import * as beautylog from 'beautylog'
import * as cflare from 'cflare'
let fs = require('fs-extra')
import * as lik from 'lik'
import * as path from 'path'
import * as q from 'q'
import * as shelljs from 'shelljs'
import * as smartcli from 'smartcli'
import * as smartfile from 'smartfile'
import * as smartgit from 'smartgit'
import * as smartstring from 'smartstring'
export {
beautylog,
cflare,
fs,
lik,
path,
q,
shelljs,
smartcli,
smartfile,
smartgit,
smartstring
}

View File

@ -1,205 +1 @@
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);
export * from './cert.classes.cert'

View File

@ -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
ts/temp Normal file
View File

@ -0,0 +1,3 @@
helpers.updateSslDirSync(this._sslDir, domainNameArg)
helpers.scheduleRetry(domainNameArg, this).then(done.resolve)
this.domainCertRequestMap.removeString(domainNameArg)