Compare commits

...

121 Commits

Author SHA1 Message Date
f70684b773 3.0.5 2020-02-21 10:48:09 +00:00
8b19b206a4 fix(core): update 2020-02-21 10:48:08 +00:00
6be2866ddd 3.0.4 2020-02-19 19:17:59 +00:00
ab55d3c91a fix(core): update 2020-02-19 19:17:58 +00:00
c7ee7eb774 3.0.3 2020-02-19 18:48:50 +00:00
02daa13a2f fix(core): update 2020-02-19 18:48:49 +00:00
28944b1100 3.0.2 2020-02-10 20:36:02 +00:00
7ec04d6d3d fix(core): update 2020-02-10 20:36:01 +00:00
595d4d8894 3.0.1 2020-02-10 20:16:50 +00:00
04ed28f7d1 fix(core): update 2020-02-10 20:16:49 +00:00
6c95cec709 3.0.0 2020-02-10 20:13:07 +00:00
59173b3ca8 BREAKING CHANGE(core): streamline scope to certificate retrieval using dns challenge 2020-02-10 20:13:06 +00:00
c2036bba90 2.1.2 2020-02-10 11:15:48 +00:00
83afea95e6 fix(core): update 2020-02-10 11:15:47 +00:00
ac515f5e80 2.1.1 2020-01-19 11:09:32 +00:00
6abbf58b83 fix(core): update 2020-01-19 11:09:32 +00:00
9c25ecdc02 2.1.0 2019-02-06 14:37:01 +01:00
81a15da2d0 feat(Cert): now has validity check 2019-02-06 14:37:00 +01:00
86929251ba update 2019-02-06 09:47:33 +01:00
1d8fb2b296 2.0.36 2019-01-18 01:35:00 +01:00
9d5f0d7a5d fix(core): update 2019-01-18 01:34:59 +01:00
82b1d68576 2.0.35 2019-01-17 22:50:22 +01:00
e04b23aceb fix(core): update 2019-01-17 22:50:21 +01:00
8e255938b5 2.0.34 2019-01-17 22:47:58 +01:00
f2eb9666a7 fix(core): update 2019-01-17 22:47:58 +01:00
cbdb0c8b08 2.0.33 2019-01-17 22:13:10 +01:00
f821f4d9cc fix(core): update 2019-01-17 22:13:10 +01:00
6cfcf21d95 2.0.32 2019-01-17 01:15:22 +01:00
a33090bb5e fix(core): update 2019-01-17 01:15:22 +01:00
3151829f85 2.0.31 2019-01-16 22:34:38 +01:00
eca63e588c fix(core): update 2019-01-16 22:34:38 +01:00
9d23e205d8 2.0.30 2019-01-16 02:34:48 +01:00
5ecdf7c9fd fix(core): update 2019-01-16 02:34:47 +01:00
2817a65e21 2.0.29 2019-01-15 23:59:21 +01:00
09a8bc5cb5 fix(core): update 2019-01-15 23:59:21 +01:00
a1134cf227 2.0.28 2019-01-15 23:39:31 +01:00
4ee1c4b08c fix(core): update 2019-01-15 23:39:31 +01:00
08c3eaa65f 2.0.27 2019-01-14 02:46:36 +01:00
2717f08476 fix(core): update 2019-01-14 02:46:36 +01:00
f16dbeea32 2.0.26 2019-01-13 21:40:40 +01:00
a0c0230419 fix(core): update 2019-01-13 21:40:40 +01:00
0d1ebf2d1a 2.0.25 2019-01-13 19:40:32 +01:00
6edbf3cb46 fix(core): update 2019-01-13 19:40:32 +01:00
b26f7ac3e9 2.0.24 2019-01-13 19:15:04 +01:00
5129c5d601 fix(core): update 2019-01-13 19:15:03 +01:00
d09b3fd1bc 2.0.23 2019-01-13 02:11:56 +01:00
14fccd40d8 fix(core): update 2019-01-13 02:11:56 +01:00
c0f45a10e0 2.0.22 2019-01-13 02:10:00 +01:00
f9db3d28fe fix(core): update 2019-01-13 02:10:00 +01:00
c3fd8750b2 2.0.21 2019-01-13 00:50:44 +01:00
2b3c28c7a1 fix(core): update 2019-01-13 00:50:43 +01:00
d6b1f942b3 2.0.20 2019-01-13 00:24:40 +01:00
7eff6ea36a fix(core): update 2019-01-13 00:24:39 +01:00
1ef3615a49 2.0.19 2019-01-13 00:06:00 +01:00
3653cdc797 fix(core): update 2019-01-13 00:06:00 +01:00
c0271648fc 2.0.18 2019-01-12 21:06:29 +01:00
5546fa5f49 fix(core): update 2019-01-12 21:06:29 +01:00
54fe89860e 2.0.17 2019-01-12 19:12:53 +01:00
d1edf75f6f fix(core): update 2019-01-12 19:12:52 +01:00
6f9c644221 2.0.16 2019-01-12 19:11:39 +01:00
0b26054687 fix(core): update 2019-01-12 19:11:39 +01:00
e3323ed4ef 2.0.15 2019-01-12 13:52:21 +01:00
24f692636c fix(core): update 2019-01-12 13:52:21 +01:00
a9f709ee7b 2.0.14 2019-01-12 13:44:18 +01:00
1b11b637a5 fix(core): update 2019-01-12 13:44:18 +01:00
ad54bf41ea 2.0.13 2019-01-09 00:01:02 +01:00
060ebf1b29 fix(core): update 2019-01-09 00:01:01 +01:00
a87c6acb8a 2.0.12 2019-01-08 20:45:36 +01:00
62d27619f4 fix(core): update 2019-01-08 20:45:35 +01:00
0faebf2a79 2.0.11 2019-01-07 12:29:11 +01:00
29ea50796c fix(core): update 2019-01-07 12:29:10 +01:00
26d1b7cbf0 2.0.10 2019-01-07 01:08:50 +01:00
c0c97835ea fix(core): update 2019-01-07 01:08:50 +01:00
d4d50b7dcf 2.0.9 2019-01-07 01:00:58 +01:00
2492fd4de2 fix(core): update 2019-01-07 01:00:58 +01:00
bef54799b6 2.0.8 2019-01-07 00:36:51 +01:00
dbe09f320a fix(core): update 2019-01-07 00:36:51 +01:00
18045dadaf 2.0.7 2019-01-06 23:54:47 +01:00
ee300c3e12 fix(core): update 2019-01-06 23:54:46 +01:00
ed4ba0cb61 2.0.6 2019-01-06 23:30:39 +01:00
a8ab27045d fix(core): update 2019-01-06 23:30:38 +01:00
975c3ed190 2.0.5 2019-01-06 20:41:43 +01:00
a99dea549b fix(core): update 2019-01-06 20:41:42 +01:00
f8b78c433a 2.0.4 2019-01-06 20:41:22 +01:00
6c33111074 fix(core): update 2019-01-06 20:41:21 +01:00
280335f6f6 2.0.3 2019-01-04 23:30:37 +01:00
b90092c043 fix(core): update 2019-01-04 23:30:37 +01:00
9e1c73febf 2.0.2 2018-10-07 21:06:28 +02:00
dcf1915816 2.0.1 2018-10-07 21:05:46 +02:00
748c911168 fix(core): update 2018-10-07 21:05:45 +02:00
3a48cb4ea8 2.0.0 2018-10-07 21:02:18 +02:00
a035c5c0b0 BREAKING CHANGE(scope): change to @pushrocks 2018-10-07 21:02:17 +02:00
f9c521b7b3 1.1.4 2018-08-12 21:45:21 +02:00
19cfe8bdc5 fix(core): update 2018-08-12 21:45:21 +02:00
601d6b30d3 1.1.3 2018-08-12 20:59:56 +02:00
57ffc82c43 1.1.2 2018-08-12 20:59:00 +02:00
312d3c01cd fix(npm publishing): update 2018-08-12 20:58:59 +02:00
8814c1fc62 1.1.1 2018-08-12 01:35:14 +02:00
223a47c997 fix(core): now creating certs all right 2018-08-12 01:35:14 +02:00
651ef6d281 1.1.0 2018-08-12 00:29:02 +02:00
9eda0da9a7 feat(swaitch to acme-v2): switch to letsencrypt v2 2018-08-12 00:29:02 +02:00
3e350dfed5 1.0.11 2017-04-28 19:01:04 +02:00
6fc280e168 add updated ci config 2017-04-28 19:00:56 +02:00
a9efae65d6 1.0.10 2017-04-28 18:59:45 +02:00
0f09bdaf9f update to latest standards 2017-04-28 18:59:43 +02:00
84177cd575 update 2017-04-28 18:56:55 +02:00
7d16ada760 1.0.9 2017-01-27 01:09:48 +01:00
b4de8cc2be basic functionality 2017-01-27 01:09:38 +01:00
68e570c32a 1.0.8 2017-01-25 02:45:52 +01:00
20ea599f9d now getting a valid response 2017-01-25 02:45:48 +01:00
5fa530456b update validation 2017-01-22 21:50:04 +01:00
2cd1794e7e improve README 2017-01-15 23:19:48 +01:00
1f38e12bd3 1.0.7 2017-01-15 23:11:54 +01:00
1c777f6f05 improve README 2017-01-15 23:11:51 +01:00
aad113a8ea add async checkDNS 2017-01-15 22:59:58 +01:00
fff63839d1 1.0.6 2017-01-15 22:30:43 +01:00
c8d2cfd4ce update to new standards 2017-01-15 22:30:33 +01:00
dfd7edd330 now has working requestValidation method 2017-01-15 13:33:55 +01:00
4dadcf227c fix som things 2017-01-15 12:21:29 +01:00
fce25c60ed start better segregation of concerns 2017-01-14 18:36:33 +01:00
98cc70dbfb start with certificate signing process 2017-01-14 14:14:50 +01:00
41 changed files with 3809 additions and 645 deletions

20
.gitignore vendored
View File

@ -1,4 +1,22 @@
node_modules/ .nogit/
# artifacts
coverage/ coverage/
public/ public/
pages/ pages/
# installs
node_modules/
# caches
.yarn/
.cache/
.rpt2_cache
# builds
dist/
dist_web/
dist_serve/
dist_ts_web/
# custom

View File

@ -1,59 +1,126 @@
image: hosttoday/ht-docker-node:npmts # gitzone ci_default
image: registry.gitlab.com/hosttoday/ht-docker-node:npmci
cache:
paths:
- .npmci_cache/
key: '$CI_BUILD_STAGE'
stages: stages:
- security
- test - test
- release - release
- trigger - metadata
- pages
testLEGACY: # ====================
# security stage
# ====================
mirror:
stage: security
script:
- npmci git mirror
tags:
- lossless
- docker
- notpriv
snyk:
image: registry.gitlab.com/hosttoday/ht-docker-node:snyk
stage: security
script:
- npmci npm prepare
- npmci command npm install --ignore-scripts
- npmci command snyk test
tags:
- lossless
- docker
- notpriv
# ====================
# test stage
# ====================
testStable:
stage: test stage: test
script: script:
- npmci test legacy - npmci npm prepare
- npmci node install stable
- npmci npm install
- npmci npm test
coverage: /\d+.?\d+?\%\s*coverage/
tags: tags:
- lossless
- docker - docker
allow_failure: true - priv
testLTS: testBuild:
stage: test stage: test
script: script:
- npmci test lts - npmci npm prepare
tags: - npmci node install stable
- docker - npmci npm install
- npmci command npm run build
testSTABLE: coverage: /\d+.?\d+?\%\s*coverage/
stage: test
script:
- npmci test stable
tags: tags:
- lossless
- docker - docker
- notpriv
release: release:
stage: release stage: release
script: script:
- npmci publish - npmci node install stable
- npmci npm publish
only: only:
- tags - tags
tags: tags:
- lossless
- docker - docker
- notpriv
# ====================
# metadata stage
# ====================
codequality:
stage: metadata
allow_failure: true
script:
- npmci command npm install -g tslint typescript
- npmci npm prepare
- npmci npm install
- npmci command "tslint -c tslint.json ./ts/**/*.ts"
tags:
- lossless
- docker
- priv
trigger: trigger:
stage: trigger stage: metadata
script: script:
- npmci trigger - npmci trigger
only: only:
- tags - tags
tags: tags:
- lossless
- docker - docker
- notpriv
pages: pages:
image: hosttoday/ht-docker-node:npmpage stage: metadata
stage: pages
script: script:
- npmci command npmpage --host gitlab - npmci node install lts
- npmci command npm install -g @gitzone/tsdoc
- npmci npm prepare
- npmci npm install
- npmci command tsdoc
tags:
- lossless
- docker
- notpriv
only: only:
- tags - tags
artifacts: artifacts:
expire_in: 1 week expire_in: 1 week
paths: paths:
- public - public
allow_failure: true

4
.npmignore Normal file
View File

@ -0,0 +1,4 @@
node_modules/
coverage/
public/
pages/

12
.snyk Normal file
View File

@ -0,0 +1,12 @@
# Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities.
version: v1.12.0
# ignores vulnerabilities until expiry date; change duration by modifying expiry date
ignore:
'npm:node-forge:20180226':
- rsa-compat > node-forge:
reason: None given
expires: '2018-09-11T19:17:24.148Z'
- acme-v2 > rsa-compat > node-forge:
reason: None given
expires: '2018-09-11T19:17:24.148Z'
patch: {}

29
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,29 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "current file",
"type": "node",
"request": "launch",
"args": [
"${relativeFile}"
],
"runtimeArgs": ["-r", "@gitzone/tsrun"],
"cwd": "${workspaceRoot}",
"protocol": "inspector",
"internalConsoleOptions": "openOnSessionStart"
},
{
"name": "test.ts",
"type": "node",
"request": "launch",
"args": [
"test/test.ts"
],
"runtimeArgs": ["-r", "@gitzone/tsrun"],
"cwd": "${workspaceRoot}",
"protocol": "inspector",
"internalConsoleOptions": "openOnSessionStart"
}
]
}

26
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,26 @@
{
"json.schemas": [
{
"fileMatch": ["/npmextra.json"],
"schema": {
"type": "object",
"properties": {
"npmci": {
"type": "object",
"description": "settings for npmci"
},
"gitzone": {
"type": "object",
"description": "settings for gitzone",
"properties": {
"projectType": {
"type": "string",
"enum": ["website", "element", "service", "npm"]
}
}
}
}
}
}
]
}

View File

@ -1,36 +0,0 @@
# smartacme
acme implementation in TypeScript
## Availabililty
[![npm](https://push.rocks/assets/repo-button-npm.svg)](https://www.npmjs.com/package/smartacme)
[![git](https://push.rocks/assets/repo-button-git.svg)](https://GitLab.com/pushrocks/smartacme)
[![git](https://push.rocks/assets/repo-button-mirror.svg)](https://github.com/pushrocks/smartacme)
[![docs](https://push.rocks/assets/repo-button-docs.svg)](https://pushrocks.gitlab.io/smartacme/)
## Status for master
[![build status](https://GitLab.com/pushrocks/smartacme/badges/master/build.svg)](https://GitLab.com/pushrocks/smartacme/commits/master)
[![coverage report](https://GitLab.com/pushrocks/smartacme/badges/master/coverage.svg)](https://GitLab.com/pushrocks/smartacme/commits/master)
[![npm downloads per month](https://img.shields.io/npm/dm/smartacme.svg)](https://www.npmjs.com/package/smartacme)
[![Dependency Status](https://david-dm.org/pushrocks/smartacme.svg)](https://david-dm.org/pushrocks/smartacme)
[![bitHound Dependencies](https://www.bithound.io/github/pushrocks/smartacme/badges/dependencies.svg)](https://www.bithound.io/github/pushrocks/smartacme/master/dependencies/npm)
[![bitHound Code](https://www.bithound.io/github/pushrocks/smartacme/badges/code.svg)](https://www.bithound.io/github/pushrocks/smartacme)
[![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
Use TypeScript for best in class instellisense.
```javascript
import { SmartAcme } from 'smartacme'
let smac = new SmartAcme()
let myAccount = smac.getAccount() // optionally accepts a filePath Arg with a stored acmeaccount.json
let myCert = myAccount.getChallenge('example.com','dns-01') // will return a dnsHash to set in your DNS record
myCert.get().then(() => {
console.log(myCert.certificate) // your certificate, ready to use in whatever way you prefer
})
```
[![npm](https://push.rocks/assets/repo-header.svg)](https://push.rocks)

1
dist/index.d.ts vendored
View File

@ -1 +0,0 @@
export * from './smartacme.classes.smartacme';

6
dist/index.js vendored
View File

@ -1,6 +0,0 @@
"use strict";
function __export(m) {
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
}
__export(require("./smartacme.classes.smartacme"));
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7O0FBQUEsbURBQTZDIn0=

View File

@ -1 +0,0 @@
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRhY21lLmNsYXNzZXMuYWNtZWFjY291bnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9zbWFydGFjbWUuY2xhc3Nlcy5hY21lYWNjb3VudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiIn0=

View File

View File

@ -1 +0,0 @@
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRhY21lLmNsYXNzZXMuYWNtZWNlcnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9zbWFydGFjbWUuY2xhc3Nlcy5hY21lY2VydC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiIn0=

View File

@ -1,21 +0,0 @@
/// <reference types="q" />
import 'typings-global';
import * as q from 'q';
import { SmartAcme } from './smartacme.classes.smartacme';
export interface IRsaKeypair {
publicKey: string;
privateKey: string;
}
export declare class SmartacmeHelper {
parentSmartAcme: SmartAcme;
constructor(smartAcmeArg: SmartAcme);
/**
* creates a keypair to use with requests and to generate JWK from
*/
createKeypair(bit?: number): IRsaKeypair;
/**
* getReg
* @executes ASYNC
*/
getReg(): q.Promise<{}>;
}

View File

@ -1,40 +0,0 @@
"use strict";
require("typings-global");
const q = require("q");
let rsaKeygen = require('rsa-keygen');
class SmartacmeHelper {
constructor(smartAcmeArg) {
this.parentSmartAcme = smartAcmeArg;
}
/**
* creates a keypair to use with requests and to generate JWK from
*/
createKeypair(bit = 2048) {
let result = rsaKeygen.generate(bit);
return {
publicKey: result.public_key,
privateKey: result.private_key
};
}
/**
* getReg
* @executes ASYNC
*/
getReg() {
let done = q.defer();
let body = { resource: 'reg' };
this.parentSmartAcme.rawacmeClient.post(this.parentSmartAcme.location, body, this.parentSmartAcme.keyPair, (err, res) => {
if (err) {
console.error('smartacme: something went wrong:');
console.log(err);
done.reject(err);
return;
}
console.log(JSON.stringify(res.body));
done.resolve();
});
return done.promise;
}
}
exports.SmartacmeHelper = SmartacmeHelper;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRhY21lLmNsYXNzZXMuaGVscGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvc21hcnRhY21lLmNsYXNzZXMuaGVscGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQSwwQkFBdUI7QUFDdkIsdUJBQXNCO0FBQ3RCLElBQUksU0FBUyxHQUFHLE9BQU8sQ0FBQyxZQUFZLENBQUMsQ0FBQTtBQVNyQztJQUdJLFlBQVksWUFBdUI7UUFDL0IsSUFBSSxDQUFDLGVBQWUsR0FBRyxZQUFZLENBQUE7SUFDdkMsQ0FBQztJQUVEOztPQUVHO0lBQ0gsYUFBYSxDQUFDLEdBQUcsR0FBRyxJQUFJO1FBQ3BCLElBQUksTUFBTSxHQUFHLFNBQVMsQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLENBQUE7UUFDcEMsTUFBTSxDQUFDO1lBQ0gsU0FBUyxFQUFFLE1BQU0sQ0FBQyxVQUFVO1lBQzVCLFVBQVUsRUFBRSxNQUFNLENBQUMsV0FBVztTQUNqQyxDQUFBO0lBQ0wsQ0FBQztJQUVEOzs7T0FHRztJQUNILE1BQU07UUFDRixJQUFJLElBQUksR0FBRyxDQUFDLENBQUMsS0FBSyxFQUFFLENBQUE7UUFDcEIsSUFBSSxJQUFJLEdBQUcsRUFBRSxRQUFRLEVBQUUsS0FBSyxFQUFFLENBQUE7UUFDOUIsSUFBSSxDQUFDLGVBQWUsQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUNuQyxJQUFJLENBQUMsZUFBZSxDQUFDLFFBQVEsRUFDN0IsSUFBSSxFQUFFLElBQUksQ0FBQyxlQUFlLENBQUMsT0FBTyxFQUNsQyxDQUFDLEdBQUcsRUFBRSxHQUFHO1lBQ0wsRUFBRSxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztnQkFDTixPQUFPLENBQUMsS0FBSyxDQUFDLGtDQUFrQyxDQUFDLENBQUE7Z0JBQ2pELE9BQU8sQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUE7Z0JBQ2hCLElBQUksQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUE7Z0JBQ2hCLE1BQU0sQ0FBQTtZQUNWLENBQUM7WUFDRCxPQUFPLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUE7WUFDckMsSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFBO1FBQ2xCLENBQUMsQ0FDSixDQUFBO1FBQ0QsTUFBTSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUE7SUFDdkIsQ0FBQztDQUNKO0FBekNELDBDQXlDQyJ9

View File

@ -1,42 +0,0 @@
/// <reference types="q" />
import 'typings-global';
import * as q from 'q';
import { SmartacmeHelper, IRsaKeypair } from './smartacme.classes.helper';
export declare type TChallenge = 'dns-01' | 'http-01';
/**
* class SmartAcme exports methods for maintaining SSL Certificates
*/
export declare class SmartAcme {
helper: SmartacmeHelper;
acmeUrl: string;
productionBool: boolean;
keyPair: IRsaKeypair;
location: string;
link: string;
rawacmeClient: any;
JWK: any;
/**
* the constructor for class SmartAcme
*/
constructor(productionArg?: boolean);
/**
* creates an account if not currently present in module
* @executes ASYNC
*/
createAccount(): q.Promise<{}>;
agreeTos(): q.Promise<{}>;
/**
* requests a challenge for a domain
* @param domainNameArg - the domain name to request a challenge for
* @param challengeType - the challenge type to request
*/
requestChallenge(domainNameArg: string, challengeTypeArg?: TChallenge): q.Promise<{}>;
/**
* getCertificate - takes care of cooldown, validation polling and certificate retrieval
*/
getCertificate(): void;
/**
* accept a challenge - for private use only
*/
private acceptChallenge(challenge);
}

File diff suppressed because one or more lines are too long

View File

@ -1,2 +0,0 @@
export declare let packageDir: string;
export declare let assetDir: string;

View File

@ -1,7 +0,0 @@
"use strict";
const path = require("path");
const smartfile = require("smartfile");
exports.packageDir = path.join(__dirname, '../');
exports.assetDir = path.join(exports.packageDir, 'assets/');
smartfile.fs.ensureDirSync(exports.assetDir);
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRhY21lLnBhdGhzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvc21hcnRhY21lLnBhdGhzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQSw2QkFBNEI7QUFDNUIsdUNBQXNDO0FBRTNCLFFBQUEsVUFBVSxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFDLEtBQUssQ0FBQyxDQUFBO0FBQ3ZDLFFBQUEsUUFBUSxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsa0JBQVUsRUFBQyxTQUFTLENBQUMsQ0FBQTtBQUNyRCxTQUFTLENBQUMsRUFBRSxDQUFDLGFBQWEsQ0FBQyxnQkFBUSxDQUFDLENBQUEifQ==

View File

@ -1,7 +1,18 @@
{ {
"gitzone": {
"projectType": "npm",
"module": {
"githost": "gitlab.com",
"gitscope": "pushrocks",
"gitrepo": "smartuniverse",
"shortDescription": "acme with an easy yet powerful interface in TypeScript",
"npmPackagename": "@pushrocks/smartuniverse",
"license": "MIT",
"projectDomain": "push.rocks"
}
},
"npmci": { "npmci": {
"globalNpmTools": [ "npmGlobalTools": [],
"npmts" "npmAccessLevel": "public"
]
} }
} }

3100
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,15 +1,17 @@
{ {
"name": "smartacme", "name": "@pushrocks/smartacme",
"version": "1.0.5", "version": "3.0.5",
"description": "acme implementation in TypeScript", "private": false,
"description": "acme with an easy yet powerful interface in TypeScript",
"main": "dist/index.js", "main": "dist/index.js",
"typings": "dist/index.d.ts", "typings": "dist/index.d.ts",
"scripts": { "scripts": {
"test": "(npmts --nodocs)" "test": "(tstest test/)",
"build": "(tsbuild)"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
"url": "git+ssh://git@gitlab.com/pushrocks/smartacme.git" "url": "git+ssh://git@gitlab.com/umbrellazone/smartacme.git"
}, },
"keywords": [ "keywords": [
"TypeScript", "TypeScript",
@ -19,21 +21,44 @@
"author": "Lossless GmbH", "author": "Lossless GmbH",
"license": "MIT", "license": "MIT",
"bugs": { "bugs": {
"url": "https://gitlab.com/pushrocks/smartacme/issues" "url": "https://gitlab.com/umbrellazone/smartacme/issues"
}, },
"homepage": "https://gitlab.com/pushrocks/smartacme#README", "homepage": "https://gitlab.com/umbrellazone/smartacme#README",
"dependencies": { "dependencies": {
"@types/q": "0.x.x", "@pushrocks/lik": "^3.0.19",
"q": "^1.4.1", "@pushrocks/smartdata": "^3.1.26",
"rawacme": "^0.2.1", "@pushrocks/smartdelay": "^2.0.6",
"rsa-keygen": "^1.0.6", "@pushrocks/smartdns": "^4.0.2",
"smartfile": "^4.1.0", "@pushrocks/smartexpress": "^3.0.57",
"smartstring": "^2.0.20", "@pushrocks/smartlog": "^2.0.21",
"typings-global": "^1.0.14" "@pushrocks/smartpromise": "^3.0.6",
"@pushrocks/smartrequest": "^1.1.47",
"@pushrocks/smartstring": "^3.0.18",
"@pushrocks/smarttime": "^3.0.12",
"@pushrocks/smartunique": "^3.0.1",
"@tsclass/tsclass": "^3.0.7",
"acme-client": "^3.3.1"
}, },
"devDependencies": { "devDependencies": {
"@types/should": "^8.1.30", "@gitzone/tsbuild": "^2.1.17",
"should": "^11.1.1", "@gitzone/tsrun": "^1.2.8",
"typings-test": "^1.0.3" "@gitzone/tstest": "^1.0.28",
} "@mojoio/cloudflare": "^4.0.3",
"@pushrocks/qenv": "^4.0.6",
"@pushrocks/tapbundle": "^3.2.0",
"@types/node": "^13.7.4",
"tslint": "^6.0.0",
"tslint-config-prettier": "^1.18.0"
},
"files": [
"ts/**/*",
"ts_web/**/*",
"dist/**/*",
"dist_web/**/*",
"dist_ts_web/**/*",
"assets/**/*",
"cli.js",
"npmextra.json",
"readme.md"
]
} }

6
qenv.yml Normal file
View File

@ -0,0 +1,6 @@
required:
- CF_EMAIL
- CF_KEY
- MONGODB_URL
- MONGODB_PASSWORD
- MONGODB_DATABASE

1
test/test.d.ts vendored
View File

@ -1 +0,0 @@
import 'typings-test';

View File

@ -1,38 +0,0 @@
"use strict";
require("typings-test");
const should = require("should");
// import the module to test
const smartacme = require("../dist/index");
describe('smartacme', function () {
let testAcme;
it('should create a valid instance', function () {
this.timeout(10000);
testAcme = new smartacme.SmartAcme();
should(testAcme).be.instanceOf(smartacme.SmartAcme);
});
it('should have created keyPair', function () {
should(testAcme.acmeUrl).be.of.type('string');
});
it('should register a new account', function (done) {
this.timeout(10000);
testAcme.createAccount().then(x => {
done();
}).catch(err => {
console.log(err);
done(err);
});
});
it('should agree to ToS', function (done) {
this.timeout(10000);
testAcme.agreeTos().then(() => {
done();
});
});
it('should request a challenge for a domain', function (done) {
this.timeout(10000);
testAcme.requestChallenge('bleu.de').then(() => {
done();
});
});
});
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGVzdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbInRlc3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLHdCQUFxQjtBQUNyQixpQ0FBZ0M7QUFFaEMsNEJBQTRCO0FBQzVCLDJDQUEwQztBQUUxQyxRQUFRLENBQUMsV0FBVyxFQUFFO0lBQ2xCLElBQUksUUFBNkIsQ0FBQTtJQUVqQyxFQUFFLENBQUMsZ0NBQWdDLEVBQUU7UUFDakMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsQ0FBQTtRQUNuQixRQUFRLEdBQUcsSUFBSSxTQUFTLENBQUMsU0FBUyxFQUFFLENBQUE7UUFDcEMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxVQUFVLENBQUMsU0FBUyxDQUFDLFNBQVMsQ0FBQyxDQUFBO0lBQ3ZELENBQUMsQ0FBQyxDQUFBO0lBRUYsRUFBRSxDQUFDLDZCQUE2QixFQUFFO1FBQzlCLE1BQU0sQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUE7SUFDakQsQ0FBQyxDQUFDLENBQUE7SUFFRixFQUFFLENBQUMsK0JBQStCLEVBQUUsVUFBVSxJQUFJO1FBQzlDLElBQUksQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUE7UUFDbkIsUUFBUSxDQUFDLGFBQWEsRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDO1lBQzNCLElBQUksRUFBRSxDQUFBO1FBQ1YsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLEdBQUc7WUFDUixPQUFPLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFBO1lBQ2hCLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQTtRQUNiLENBQUMsQ0FBQyxDQUFBO0lBQ04sQ0FBQyxDQUFDLENBQUE7SUFFRixFQUFFLENBQUMscUJBQXFCLEVBQUUsVUFBUyxJQUFJO1FBQ25DLElBQUksQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUE7UUFDbkIsUUFBUSxDQUFDLFFBQVEsRUFBRSxDQUFDLElBQUksQ0FBQztZQUNyQixJQUFJLEVBQUUsQ0FBQTtRQUNWLENBQUMsQ0FBQyxDQUFBO0lBQ04sQ0FBQyxDQUFDLENBQUE7SUFFRixFQUFFLENBQUMseUNBQXlDLEVBQUUsVUFBUyxJQUFJO1FBQ3ZELElBQUksQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUE7UUFDbkIsUUFBUSxDQUFDLGdCQUFnQixDQUFDLFNBQVMsQ0FBQyxDQUFDLElBQUksQ0FBQztZQUN0QyxJQUFJLEVBQUUsQ0FBQTtRQUNWLENBQUMsQ0FBQyxDQUFBO0lBQ04sQ0FBQyxDQUFDLENBQUE7QUFDTixDQUFDLENBQUMsQ0FBQSJ9

View File

@ -1,43 +1,50 @@
import 'typings-test' import { tap, expect } from '@pushrocks/tapbundle';
import * as should from 'should' import { Qenv } from '@pushrocks/qenv';
import * as cloudflare from '@mojoio/cloudflare';
// import the module to test const testQenv = new Qenv('./', './.nogit/');
import * as smartacme from '../dist/index' const testCloudflare = new cloudflare.CloudflareAccount({
email: testQenv.getEnvVarOnDemand('CF_EMAIL'),
key: testQenv.getEnvVarOnDemand('CF_KEY')
});
describe('smartacme', function () { import * as smartacme from '../ts/index';
let testAcme: smartacme.SmartAcme
it('should create a valid instance', function () { let smartAcmeInstance: smartacme.SmartAcme;
this.timeout(10000)
testAcme = new smartacme.SmartAcme()
should(testAcme).be.instanceOf(smartacme.SmartAcme)
})
it('should have created keyPair', function () { tap.test('should create a valid instance of SmartAcme', async () => {
should(testAcme.acmeUrl).be.of.type('string') smartAcmeInstance = new smartacme.SmartAcme({
}) accountEmail: 'domains@lossless.org',
accountPrivateKey: null,
mongoDescriptor: {
mongoDbName: testQenv.getEnvVarRequired('MONGODB_DATABASE'),
mongoDbPass: testQenv.getEnvVarRequired('MONGODB_PASSWORD'),
mongoDbUrl: testQenv.getEnvVarRequired('MONGODB_URL')
},
removeChallenge: async dnsChallenge => {
testCloudflare.convenience.acmeRemoveDnsChallenge(dnsChallenge);
},
setChallenge: async dnsChallenge => {
testCloudflare.convenience.acmeSetDnsChallenge(dnsChallenge);
},
environment: 'integration'
});
await smartAcmeInstance.init();
});
it('should register a new account', function (done) { tap.test('should get a domain certificate', async () => {
this.timeout(10000) await smartAcmeInstance.getCertificateForDomain('bleu.de');
testAcme.createAccount().then(x => { });
done()
}).catch(err => {
console.log(err)
done(err)
})
})
it('should agree to ToS', function(done) { tap.test('certmatcher should correctly match domains', async () => {
this.timeout(10000) const certMatcherMod = await import('../ts/smartacme.classes.certmatcher');
testAcme.agreeTos().then(() => { const certMatcher = new certMatcherMod.CertMatcher();
done() const matchedCert = certMatcher.getCertificateDomainNameByDomainName('level3.level2.level1');
}) expect(matchedCert).to.equal('level2.level1');
}) });
it('should request a challenge for a domain', function(done) { tap.test('should stop correctly', async () => {
this.timeout(10000) await smartAcmeInstance.stop();
testAcme.requestChallenge('bleu.de').then(() => { });
done()
}) tap.start();
})
})

View File

@ -1 +1 @@
export * from './smartacme.classes.smartacme' export * from './smartacme.classes.smartacme';

View File

@ -0,0 +1,8 @@
export interface IAccountData {
id: number;
key: { kty: 'RSA'; n: string; e: string; kid: string };
contact: string[];
initialIp: string;
createdAt: string;
status: string;
}

1
ts/interfaces/index.ts Normal file
View File

@ -0,0 +1 @@
export * from './accountdata';

View File

@ -1,5 +0,0 @@
import 'typings-global'
export class AcmeAccount {
}

View File

@ -1,5 +0,0 @@
import 'typings-global'
export class AcmeCert {
}

View File

@ -0,0 +1,62 @@
import * as plugins from './smartacme.plugins';
import * as interfaces from './interfaces';
import { CertManager } from './smartacme.classes.certmanager';
import { Collection, svDb, unI } from '@pushrocks/smartdata';
@plugins.smartdata.Collection(() => {
return CertManager.activeDB;
})
export class Cert extends plugins.smartdata.SmartDataDbDoc<Cert, plugins.tsclass.network.ICert>
implements plugins.tsclass.network.ICert {
@unI()
public id: string;
@svDb()
public domainName: string;
@svDb()
public created: number;
@svDb()
public privateKey: string;
@svDb()
public publicKey: string;
@svDb()
public csr: string;
@svDb()
public validUntil: number;
public isStillValid(): boolean {
return this.validUntil >= Date.now();
}
public shouldBeRenewed(): boolean {
const shouldBeValidAtLeastUntil =
Date.now() +
plugins.smarttime.getMilliSecondsFromUnits({
days: 10
});
return !(this.validUntil >= shouldBeValidAtLeastUntil);
}
public update(certDataArg: plugins.tsclass.network.ICert) {
Object.keys(certDataArg).forEach(key => {
this[key] = certDataArg[key];
});
}
constructor(optionsArg: plugins.tsclass.network.ICert) {
super();
if (optionsArg) {
Object.keys(optionsArg).forEach(key => {
this[key] = optionsArg[key];
});
}
}
}

View File

@ -0,0 +1,77 @@
import * as plugins from './smartacme.plugins';
import { Cert } from './smartacme.classes.cert';
import { SmartAcme } from './smartacme.classes.smartacme';
import * as interfaces from './interfaces';
export class CertManager {
// =========
// STATIC
// =========
public static activeDB: plugins.smartdata.SmartdataDb;
// =========
// INSTANCE
// =========
private mongoDescriptor: plugins.smartdata.IMongoDescriptor;
public smartdataDb: plugins.smartdata.SmartdataDb;
public interestMap: plugins.lik.InterestMap<string, Cert>;
constructor(
smartAcmeArg: SmartAcme,
optionsArg: {
mongoDescriptor: plugins.smartdata.IMongoDescriptor;
}
) {
this.mongoDescriptor = optionsArg.mongoDescriptor;
}
public async init() {
// Smartdata DB
this.smartdataDb = new plugins.smartdata.SmartdataDb(this.mongoDescriptor);
await this.smartdataDb.init();
CertManager.activeDB = this.smartdataDb;
// Pending Map
this.interestMap = new plugins.lik.InterestMap(certName => certName);
}
/**
* retrieves a certificate
* @returns the Cert class or null
* @param certDomainNameArg the domain Name to retrieve the vcertificate for
*/
public async retrieveCertificate(certDomainNameArg: string): Promise<Cert> {
const existingCertificate: Cert = await Cert.getInstance({
domainName: certDomainNameArg
});
if (existingCertificate) {
return existingCertificate;
} else {
return null;
}
}
/**
* stores the certificate
* @param optionsArg
*/
public async storeCertificate(optionsArg: plugins.tsclass.network.ICert) {
const cert = new Cert(optionsArg);
await cert.save();
const interest = this.interestMap.findInterest(cert.domainName);
if (interest) {
interest.fullfillInterest(cert);
interest.markLost();
}
}
public async deleteCertificate(certDomainNameArg: string) {
const cert: Cert = await Cert.getInstance({
domainName: certDomainNameArg
});
await cert.delete();
}
}

View File

@ -0,0 +1,19 @@
import * as plugins from './smartacme.plugins';
import * as interfaces from './interfaces';
/**
* certmatcher is responsible for matching certificates
*/
export class CertMatcher {
/**
* creates a domainName for the certificate that will include the broadest scope
* for wild card certificates
* @param domainNameArg the domainNameArg to create the scope from
*/
public getCertificateDomainNameByDomainName(domainNameArg: string): string {
const originalDomain = new plugins.smartstring.Domain(domainNameArg);
if (!originalDomain.level4) {
return `${originalDomain.level2}.${originalDomain.level1}`;
}
}
}

View File

@ -1,53 +0,0 @@
import 'typings-global'
import * as q from 'q'
let rsaKeygen = require('rsa-keygen')
import { SmartAcme } from './smartacme.classes.smartacme'
export interface IRsaKeypair {
publicKey: string
privateKey: string
}
export class SmartacmeHelper {
parentSmartAcme: SmartAcme
constructor(smartAcmeArg: SmartAcme) {
this.parentSmartAcme = smartAcmeArg
}
/**
* creates a keypair to use with requests and to generate JWK from
*/
createKeypair(bit = 2048): IRsaKeypair {
let result = rsaKeygen.generate(bit)
return {
publicKey: result.public_key,
privateKey: result.private_key
}
}
/**
* getReg
* @executes ASYNC
*/
getReg() {
let done = q.defer()
let body = { resource: 'reg' }
this.parentSmartAcme.rawacmeClient.post(
this.parentSmartAcme.location,
body, this.parentSmartAcme.keyPair,
(err, res) => {
if (err) {
console.error('smartacme: something went wrong:')
console.log(err)
done.reject(err)
return
}
console.log(JSON.stringify(res.body))
done.resolve()
}
)
return done.promise
}
}

View File

@ -1,178 +1,214 @@
import 'typings-global' import * as plugins from './smartacme.plugins';
import * as q from 'q' import { Cert } from './smartacme.classes.cert';
import * as path from 'path' import { CertManager } from './smartacme.classes.certmanager';
let rsaKeygen = require('rsa-keygen') import { CertMatcher } from './smartacme.classes.certmatcher';
import * as smartfile from 'smartfile'
import * as smartstring from 'smartstring'
let rawacme = require('rawacme')
import * as paths from './smartacme.paths'
import { SmartacmeHelper, IRsaKeypair } from './smartacme.classes.helper'
export type TChallenge = 'dns-01' | 'http-01'
/** /**
* class SmartAcme exports methods for maintaining SSL Certificates * the options for the class @see SmartAcme
*/
export interface ISmartAcmeOptions {
accountPrivateKey?: string;
accountEmail: string;
mongoDescriptor: plugins.smartdata.IMongoDescriptor;
setChallenge: (dnsChallengeArg: plugins.tsclass.network.IDnsChallenge) => Promise<any>;
removeChallenge: (dnsChallengeArg: plugins.tsclass.network.IDnsChallenge) => Promise<any>;
environment: 'production' | 'integration';
logger?: plugins.smartlog.Smartlog;
}
/**
* class SmartAcme
* can be used for setting up communication with an ACME authority
*
* ```ts
* const mySmartAcmeInstance = new SmartAcme({
* // see ISmartAcmeOptions for options
* })
* ```
*/ */
export class SmartAcme { export class SmartAcme {
helper: SmartacmeHelper // bundles helper methods that would clutter the main SmartAcme class private options: ISmartAcmeOptions;
acmeUrl: string // the acme url to use
productionBool: boolean // a boolean to quickly know wether we are in production or not // the acme client
keyPair: IRsaKeypair // the keyPair needed for account creation private client: any;
location: string private smartdns = new plugins.smartdns.Smartdns({});
link: string public logger: plugins.smartlog.Smartlog;
rawacmeClient
JWK // the account private key
private privateKey: string;
// challenge fullfillment
private setChallenge: (dnsChallengeArg: plugins.tsclass.network.IDnsChallenge) => Promise<any>;
private removeChallenge: (dnsChallengeArg: plugins.tsclass.network.IDnsChallenge) => Promise<any>;
// certmanager
private certmanager: CertManager;
private certmatcher: CertMatcher;
constructor(optionsArg: ISmartAcmeOptions) {
this.options = optionsArg;
this.options.logger
? (this.logger = optionsArg.logger)
: (this.logger = plugins.smartlog.defaultLogger);
}
/** /**
* the constructor for class SmartAcme * inits the instance
* ```ts
* await myCloudlyInstance.init() // does not support options
* ```
*/ */
constructor(productionArg: boolean = false) { public async init() {
this.productionBool = productionArg this.privateKey =
this.helper = new SmartacmeHelper(this) this.options.accountPrivateKey || (await plugins.acme.forge.createPrivateKey()).toString();
this.keyPair = this.helper.createKeypair() this.setChallenge = this.options.setChallenge;
if (this.productionBool) { this.removeChallenge = this.options.removeChallenge;
this.acmeUrl = rawacme.LETSENCRYPT_URL
// CertMangaer
this.certmanager = new CertManager(this, {
mongoDescriptor: this.options.mongoDescriptor
});
await this.certmanager.init();
// CertMatcher
this.certmatcher = new CertMatcher();
// ACME Client
this.client = new plugins.acme.Client({
directoryUrl: (() => {
if (this.options.environment === 'production') {
return plugins.acme.directory.letsencrypt.production;
} else { } else {
this.acmeUrl = rawacme.LETSENCRYPT_STAGING_URL return plugins.acme.directory.letsencrypt.staging;
} }
})(),
accountKey: this.privateKey
});
/* Register account */
await this.client.createAccount({
termsOfServiceAgreed: true,
contact: [`mailto:${this.options.accountEmail}`]
});
}
public async stop() {
await this.certmanager.smartdataDb.close();
} }
/** /**
* creates an account if not currently present in module * gets a certificate
* @executes ASYNC * it runs through the following steps
*
* * look in the database
* * if in the database and still valid return it
* * if not in the database announce it
* * then get it from letsencrypt
* * store it
* * remove it from the pending map (which it go onto by announcing it)
* * retrieve it from the databse and return it
*
* @param domainArg
*/ */
createAccount() { public async getCertificateForDomain(domainArg: string): Promise<Cert> {
let done = q.defer() const certDomainName = this.certmatcher.getCertificateDomainNameByDomainName(domainArg);
rawacme.createClient( const retrievedCertificate = await this.certmanager.retrieveCertificate(certDomainName);
{
url: this.acmeUrl, if (
publicKey: this.keyPair.publicKey, !retrievedCertificate &&
privateKey: this.keyPair.privateKey (await this.certmanager.interestMap.checkInterest(certDomainName))
}, ) {
(err, client) => { const existingCertificateInterest = this.certmanager.interestMap.findInterest(certDomainName);
if (err) { const certificate = existingCertificateInterest.interestFullfilled;
console.error('smartacme: something went wrong:') return certificate;
console.log(err) } else if (retrievedCertificate && !retrievedCertificate.shouldBeRenewed()) {
done.reject(err) return retrievedCertificate;
return } else if (retrievedCertificate && retrievedCertificate.shouldBeRenewed()) {
// await retrievedCertificate.delete();
} }
// make client available in class // lets make sure others get the same interest
this.rawacmeClient = client const currentDomainInterst = await this.certmanager.interestMap.addInterest(certDomainName);
// create the registration /* Place new order */
client.newReg( const order = await this.client.createOrder({
{ identifiers: [
contact: ['mailto:domains@lossless.org'] { type: 'dns', value: certDomainName },
}, { type: 'dns', value: `*.${certDomainName}` }
(err, res) => { ]
if (err) { });
console.error('smartacme: something went wrong:')
console.log(err) /* Get authorizations and select challenges */
done.reject(err) const authorizations = await this.client.getAuthorizations(order);
return
for (const authz of authorizations) {
console.log(authz);
const fullHostName: string = `_acme-challenge.${authz.identifier.value}`;
const dnsChallenge: string = authz.challenges.find(challengeArg => {
return challengeArg.type === 'dns-01';
});
// process.exit(1);
const keyAuthorization: string = await this.client.getChallengeKeyAuthorization(dnsChallenge);
try {
/* Satisfy challenge */
await this.setChallenge({
hostName: fullHostName,
challenge: keyAuthorization
});
await this.smartdns.checkUntilAvailable(fullHostName, 'TXT', keyAuthorization, 100, 5000);
console.log('Cool down an extra 60 second for region availability');
await plugins.smartdelay.delayFor(60000);
/* Verify that challenge is satisfied */
await this.client.verifyChallenge(authz, dnsChallenge);
/* Notify ACME provider that challenge is satisfied */
await this.client.completeChallenge(dnsChallenge);
/* Wait for ACME provider to respond with valid status */
await this.client.waitForValidStatus(dnsChallenge);
} finally {
/* Clean up challenge response */
try {
await this.removeChallenge({
hostName: fullHostName,
challenge: keyAuthorization
});
} catch (e) {
console.log(e);
} }
this.JWK = res.body.key }
this.link = res.headers.link }
console.log(this.link)
this.location = res.headers.location /* Finalize order */
done.resolve() const [key, csr] = await plugins.acme.forge.createCsr({
commonName: `*.${certDomainName}`,
altNames: [certDomainName]
});
await this.client.finalizeOrder(order, csr);
const cert = await this.client.getCertificate(order);
/* Done */
await this.certmanager.storeCertificate({
id: plugins.smartunique.shortId(),
domainName: certDomainName,
privateKey: key.toString(),
publicKey: cert.toString(),
csr: csr.toString(),
created: Date.now(),
validUntil:
Date.now() +
plugins.smarttime.getMilliSecondsFromUnits({
days: 90
}) })
});
const newCertificate = await this.certmanager.retrieveCertificate(certDomainName);
currentDomainInterst.fullfillInterest(newCertificate);
currentDomainInterst.destroy();
return newCertificate;
} }
)
return done.promise
}
agreeTos() {
let done = q.defer()
let tosPart = this.link.split(',')[1]
let tosLinkPortion = tosPart.split(';')[0]
let url = tosLinkPortion.split(';')[0].trim().replace(/[<>]/g, '')
this.rawacmeClient.post(this.location, { Agreement: url, resource: 'reg' }, (err, res) => {
if (err) {
console.log(err)
done.reject(err)
return
}
done.resolve()
})
return done.promise
}
/**
* requests a challenge for a domain
* @param domainNameArg - the domain name to request a challenge for
* @param challengeType - the challenge type to request
*/
requestChallenge(domainNameArg: string, challengeTypeArg: TChallenge = 'dns-01') {
let done = q.defer()
this.rawacmeClient.newAuthz(
{
identifier: {
type: 'dns',
value: domainNameArg
}
},
this.keyPair,
(err, res) => {
if (err) {
console.error('smartacme: something went wrong:')
console.log(err)
done.reject(err)
}
console.log(JSON.stringify(res.body))
let dnsChallenge = res.body.challenges.filter(x => {
return x.type === challengeTypeArg
})[0]
this.acceptChallenge(dnsChallenge)
.then(x => {
done.resolve(x)
})
}
)
return done.promise
}
/**
* getCertificate - takes care of cooldown, validation polling and certificate retrieval
*/
getCertificate() {
}
/**
* accept a challenge - for private use only
*/
private acceptChallenge(challenge) {
let done = q.defer()
let authKey: string = rawacme.keyAuthz(challenge.token, this.keyPair.publicKey)
let dnsKeyHash: string = rawacme.dnsKeyAuthzHash(authKey) // needed if dns challenge is chosen
console.log(authKey)
this.rawacmeClient.post(
challenge.uri,
{
resource: 'challenge',
keyAuthorization: authKey
},
this.keyPair,
(err, res) => {
if (err) {
console.log(err)
done.reject(err)
}
console.log('acceptChallenge:')
console.log(JSON.stringify(res.body))
done.resolve(dnsKeyHash)
}
)
return done.promise
}
} }

View File

@ -1,6 +0,0 @@
import * as path from 'path'
import * as smartfile from 'smartfile'
export let packageDir = path.join(__dirname,'../')
export let assetDir = path.join(packageDir,'assets/')
smartfile.fs.ensureDirSync(assetDir)

36
ts/smartacme.plugins.ts Normal file
View File

@ -0,0 +1,36 @@
// @pushrocks scope
import * as lik from '@pushrocks/lik';
import * as smartdata from '@pushrocks/smartdata';
import * as smartdelay from '@pushrocks/smartdelay';
import * as smartdns from '@pushrocks/smartdns';
import * as smartexpress from '@pushrocks/smartexpress';
import * as smartlog from '@pushrocks/smartlog';
import * as smartpromise from '@pushrocks/smartpromise';
import * as smartrequest from '@pushrocks/smartrequest';
import * as smartunique from '@pushrocks/smartunique';
import * as smartstring from '@pushrocks/smartstring';
import * as smarttime from '@pushrocks/smarttime';
export {
lik,
smartdata,
smartdelay,
smartdns,
smartexpress,
smartlog,
smartpromise,
smartrequest,
smartunique,
smartstring,
smarttime
};
// @tsclass scope
import * as tsclass from '@tsclass/tsclass';
export { tsclass };
// third party scope
import * as acme from 'acme-client';
export { acme };

View File

7
tsconfig.json Normal file
View File

@ -0,0 +1,7 @@
{
"compilerOptions": {
"experimentalDecorators": true,
"target": "es2017",
"module": "commonjs"
}
}

View File

@ -1,3 +1,17 @@
{ {
"extends": "tslint-config-standard" "extends": ["tslint:latest", "tslint-config-prettier"],
"rules": {
"semicolon": [true, "always"],
"no-console": false,
"ordered-imports": false,
"object-literal-sort-keys": false,
"member-ordering": {
"options":{
"order": [
"static-method"
]
}
}
},
"defaultSeverity": "warning"
} }