Compare commits
6 Commits
Author | SHA1 | Date | |
---|---|---|---|
89d628bd37 | |||
0056c8508c | |||
96e0c4f905 | |||
2f844dd78d | |||
ab82ac0c83 | |||
5b925e3d1b |
12
README.md
12
README.md
@ -21,4 +21,16 @@ acme implementation in TypeScript
|
|||||||
## Usage
|
## Usage
|
||||||
Use TypeScript for best in class instellisense.
|
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
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
[](https://push.rocks)
|
[](https://push.rocks)
|
||||||
|
@ -1,27 +0,0 @@
|
|||||||
-----BEGIN RSA PRIVATE KEY-----
|
|
||||||
MIIEpQIBAAKCAQEAyocFq3vvbiRNCsEcXtsqimIi6UM1OmxiYVQ0NoLvBtpaWk+E
|
|
||||||
TvNIjmUgh5QQaQfRyRGoWvhskp+E8p6go4GsbRtzx0TvL8uINTcC3SHHo6Qvl599
|
|
||||||
4QUUPUrioHdh+lX1oj+zIPVUOaL4dl0US1Ebs5vrZVbCfNXSm86vBaPIj6IkWEkj
|
|
||||||
4S5xGsYlVaQUI8Tvv2fbPziIivbkxS1v/EEMnfk6i5PWgCsnMupYxz58WaVp9xyu
|
|
||||||
+v/DMPB09mqo4DzchtUNF/b5eOWh3pDJoewYyRVMDDPJoQiTKkJn3kt64EaQuZK2
|
|
||||||
nUXcihlmaKIx5ayxirsgfvIvxidHnkQcluvciQIDAQABAoIBAQCTPUKz/3B8pMuW
|
|
||||||
C/syQyhUXzB+YawrA20q0Wr8Toi0dL7HdZP9SgXv8DmMF+suUM8F3V6GdKGKn4qq
|
|
||||||
UQT8mmPfFtw/fTBfkRs/hPUCC3L214D6PKvpkiW6wdytSN3kf+YKxUDXr0RCeuck
|
|
||||||
NltwvlDjbXHfxQm0dEefms3HzeEb+jwCyyLVLv+cDly7w7Qqq+67A6mduV/hb53p
|
|
||||||
92VFm36r7njr+1CYHq+ixV+oyUrEue7yW7w1SjZRkii3AY8Tbvk1f0lVw+XkyYf7
|
|
||||||
bQvmGSGJh1FmBi7Lytc2hKnqBLTn+iWx3S5pdPhcKTMwC/OD8p+r/DfyqThW/KVa
|
|
||||||
aaXdoY/5AoGBAO4uAcmHOhR+M/Jnue4srZJ82EkNOQy+zaFlg9KCU9R4qZ59/klH
|
|
||||||
fp0PkOw3bDFT4/1i12nm4XXqhI9Z7nsKdAoajOYpnifJVEAwQh9MlRBM7Lw+ZS0q
|
|
||||||
IcH7dvvP1XQ7E2U4C0cWUMcpWNpnmwV67gtqy0KZwk5i+WlFuugQzmhbAoGBANmu
|
|
||||||
JX6bPKUx0kBJLWhJeAxsk0OoHJ4uGihs1zxT6gl6s+AKQG4db9vU2w99lJ0nR3Aw
|
|
||||||
MLA4evSMFa5Od96W4KnoiMNHS4c5QiiVKsRSU1losWfwq0jyg406oyTh8rd0eOQn
|
|
||||||
LDOKP7nDTij8A6l0/t5a2MCu4bLQQXTedPrX+wPrAoGBAM/XO94Fb+xUGLaOR1SM
|
|
||||||
jkaHRSGyNTdnBP+zGy5GZirBxJo2rgB6MAWUgM1wq6v73bbOWtXiEJqaNGT3gEDE
|
|
||||||
ZXAvrQZoCMgFSszcj8bKSEW6Ktc1x4p6+oxRCIpC2aycpJcuKcE1uvWgohWsVT2a
|
|
||||||
AUHbRlXu4P0QJz7zB1/c0pGDAoGAbIvSVpfCXf3CAhx7cA1yt39Mz+f8nUQP9yiP
|
|
||||||
C54sjh2JpKZ4CnDTXqN9uPO+L79ueBsPrE/9wAQ6q3ilfXFvBkrWJ8pdd0iuHN6F
|
|
||||||
PPBwb50tGc+BGhcUUlBzGekxxxllTx/ZgrnlnRQu3XENwmp8zRQwEaUjFq+SdFyZ
|
|
||||||
qJwap5ECgYEA7UGxxRXAjfStTLnsrnr9svvr3QhwnZBg5JAjeR6FKC0cGFzdBrJ5
|
|
||||||
rV/Zy4mGbTBBVh5oU3MplB3AUHejuFv+8eCik2mJug8k3G8KQAk9mB8oV97k0cp+
|
|
||||||
bdlu9vlutIoCG9RXxCHdgRVLiLK+OkLv6p7hQOIY7fsIRaAuI+vPKSk=
|
|
||||||
-----END RSA PRIVATE KEY-----
|
|
@ -1,9 +0,0 @@
|
|||||||
-----BEGIN PUBLIC KEY-----
|
|
||||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyocFq3vvbiRNCsEcXtsq
|
|
||||||
imIi6UM1OmxiYVQ0NoLvBtpaWk+ETvNIjmUgh5QQaQfRyRGoWvhskp+E8p6go4Gs
|
|
||||||
bRtzx0TvL8uINTcC3SHHo6Qvl5994QUUPUrioHdh+lX1oj+zIPVUOaL4dl0US1Eb
|
|
||||||
s5vrZVbCfNXSm86vBaPIj6IkWEkj4S5xGsYlVaQUI8Tvv2fbPziIivbkxS1v/EEM
|
|
||||||
nfk6i5PWgCsnMupYxz58WaVp9xyu+v/DMPB09mqo4DzchtUNF/b5eOWh3pDJoewY
|
|
||||||
yRVMDDPJoQiTKkJn3kt64EaQuZK2nUXcihlmaKIx5ayxirsgfvIvxidHnkQcluvc
|
|
||||||
iQIDAQAB
|
|
||||||
-----END PUBLIC KEY-----
|
|
0
dist/smartacme.classes.acmeaccount.d.ts
vendored
Normal file
0
dist/smartacme.classes.acmeaccount.d.ts
vendored
Normal file
1
dist/smartacme.classes.acmeaccount.js
vendored
Normal file
1
dist/smartacme.classes.acmeaccount.js
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRhY21lLmNsYXNzZXMuYWNtZWFjY291bnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9zbWFydGFjbWUuY2xhc3Nlcy5hY21lYWNjb3VudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiIn0=
|
0
dist/smartacme.classes.acmecert.d.ts
vendored
Normal file
0
dist/smartacme.classes.acmecert.d.ts
vendored
Normal file
1
dist/smartacme.classes.acmecert.js
vendored
Normal file
1
dist/smartacme.classes.acmecert.js
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRhY21lLmNsYXNzZXMuYWNtZWNlcnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9zbWFydGFjbWUuY2xhc3Nlcy5hY21lY2VydC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiIn0=
|
13
dist/smartacme.classes.helper.d.ts
vendored
13
dist/smartacme.classes.helper.d.ts
vendored
@ -1,8 +1,21 @@
|
|||||||
|
/// <reference types="q" />
|
||||||
import 'typings-global';
|
import 'typings-global';
|
||||||
|
import * as q from 'q';
|
||||||
|
import { SmartAcme } from './smartacme.classes.smartacme';
|
||||||
export interface IRsaKeypair {
|
export interface IRsaKeypair {
|
||||||
publicKey: string;
|
publicKey: string;
|
||||||
privateKey: string;
|
privateKey: string;
|
||||||
}
|
}
|
||||||
export declare class SmartacmeHelper {
|
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;
|
createKeypair(bit?: number): IRsaKeypair;
|
||||||
|
/**
|
||||||
|
* getReg
|
||||||
|
* @executes ASYNC
|
||||||
|
*/
|
||||||
|
getReg(): q.Promise<{}>;
|
||||||
}
|
}
|
||||||
|
28
dist/smartacme.classes.helper.js
vendored
28
dist/smartacme.classes.helper.js
vendored
@ -1,7 +1,14 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
require("typings-global");
|
require("typings-global");
|
||||||
|
const q = require("q");
|
||||||
let rsaKeygen = require('rsa-keygen');
|
let rsaKeygen = require('rsa-keygen');
|
||||||
class SmartacmeHelper {
|
class SmartacmeHelper {
|
||||||
|
constructor(smartAcmeArg) {
|
||||||
|
this.parentSmartAcme = smartAcmeArg;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* creates a keypair to use with requests and to generate JWK from
|
||||||
|
*/
|
||||||
createKeypair(bit = 2048) {
|
createKeypair(bit = 2048) {
|
||||||
let result = rsaKeygen.generate(bit);
|
let result = rsaKeygen.generate(bit);
|
||||||
return {
|
return {
|
||||||
@ -9,6 +16,25 @@ class SmartacmeHelper {
|
|||||||
privateKey: result.private_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;
|
exports.SmartacmeHelper = SmartacmeHelper;
|
||||||
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRhY21lLmNsYXNzZXMuaGVscGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvc21hcnRhY21lLmNsYXNzZXMuaGVscGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQSwwQkFBdUI7QUFDdkIsSUFBSSxTQUFTLEdBQUcsT0FBTyxDQUFDLFlBQVksQ0FBQyxDQUFBO0FBT3JDO0lBQ0ksYUFBYSxDQUFDLEdBQUcsR0FBRyxJQUFJO1FBQ3BCLElBQUksTUFBTSxHQUFHLFNBQVMsQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLENBQUE7UUFDbkMsTUFBTSxDQUFDO1lBQ0osU0FBUyxFQUFHLE1BQU0sQ0FBQyxVQUFVO1lBQzdCLFVBQVUsRUFBRSxNQUFNLENBQUMsV0FBVztTQUNoQyxDQUFBO0lBQ04sQ0FBQztDQUNKO0FBUkQsMENBUUMifQ==
|
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRhY21lLmNsYXNzZXMuaGVscGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvc21hcnRhY21lLmNsYXNzZXMuaGVscGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQSwwQkFBdUI7QUFDdkIsdUJBQXNCO0FBQ3RCLElBQUksU0FBUyxHQUFHLE9BQU8sQ0FBQyxZQUFZLENBQUMsQ0FBQTtBQVNyQztJQUdJLFlBQVksWUFBdUI7UUFDL0IsSUFBSSxDQUFDLGVBQWUsR0FBRyxZQUFZLENBQUE7SUFDdkMsQ0FBQztJQUVEOztPQUVHO0lBQ0gsYUFBYSxDQUFDLEdBQUcsR0FBRyxJQUFJO1FBQ3BCLElBQUksTUFBTSxHQUFHLFNBQVMsQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLENBQUE7UUFDcEMsTUFBTSxDQUFDO1lBQ0gsU0FBUyxFQUFFLE1BQU0sQ0FBQyxVQUFVO1lBQzVCLFVBQVUsRUFBRSxNQUFNLENBQUMsV0FBVztTQUNqQyxDQUFBO0lBQ0wsQ0FBQztJQUVEOzs7T0FHRztJQUNILE1BQU07UUFDRixJQUFJLElBQUksR0FBRyxDQUFDLENBQUMsS0FBSyxFQUFFLENBQUE7UUFDcEIsSUFBSSxJQUFJLEdBQUcsRUFBRSxRQUFRLEVBQUUsS0FBSyxFQUFFLENBQUE7UUFDOUIsSUFBSSxDQUFDLGVBQWUsQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUNuQyxJQUFJLENBQUMsZUFBZSxDQUFDLFFBQVEsRUFDN0IsSUFBSSxFQUFFLElBQUksQ0FBQyxlQUFlLENBQUMsT0FBTyxFQUNsQyxDQUFDLEdBQUcsRUFBRSxHQUFHO1lBQ0wsRUFBRSxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztnQkFDTixPQUFPLENBQUMsS0FBSyxDQUFDLGtDQUFrQyxDQUFDLENBQUE7Z0JBQ2pELE9BQU8sQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUE7Z0JBQ2hCLElBQUksQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUE7Z0JBQ2hCLE1BQU0sQ0FBQTtZQUNWLENBQUM7WUFDRCxPQUFPLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUE7WUFDckMsSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFBO1FBQ2xCLENBQUMsQ0FDSixDQUFBO1FBQ0QsTUFBTSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUE7SUFDdkIsQ0FBQztDQUNKO0FBekNELDBDQXlDQyJ9
|
19
dist/smartacme.classes.smartacme.d.ts
vendored
19
dist/smartacme.classes.smartacme.d.ts
vendored
@ -2,6 +2,7 @@
|
|||||||
import 'typings-global';
|
import 'typings-global';
|
||||||
import * as q from 'q';
|
import * as q from 'q';
|
||||||
import { SmartacmeHelper, IRsaKeypair } from './smartacme.classes.helper';
|
import { SmartacmeHelper, IRsaKeypair } from './smartacme.classes.helper';
|
||||||
|
export declare type TChallenge = 'dns-01' | 'http-01';
|
||||||
/**
|
/**
|
||||||
* class SmartAcme exports methods for maintaining SSL Certificates
|
* class SmartAcme exports methods for maintaining SSL Certificates
|
||||||
*/
|
*/
|
||||||
@ -10,6 +11,9 @@ export declare class SmartAcme {
|
|||||||
acmeUrl: string;
|
acmeUrl: string;
|
||||||
productionBool: boolean;
|
productionBool: boolean;
|
||||||
keyPair: IRsaKeypair;
|
keyPair: IRsaKeypair;
|
||||||
|
location: string;
|
||||||
|
link: string;
|
||||||
|
rawacmeClient: any;
|
||||||
JWK: any;
|
JWK: any;
|
||||||
/**
|
/**
|
||||||
* the constructor for class SmartAcme
|
* the constructor for class SmartAcme
|
||||||
@ -20,4 +24,19 @@ export declare class SmartAcme {
|
|||||||
* @executes ASYNC
|
* @executes ASYNC
|
||||||
*/
|
*/
|
||||||
createAccount(): q.Promise<{}>;
|
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);
|
||||||
}
|
}
|
||||||
|
86
dist/smartacme.classes.smartacme.js
vendored
86
dist/smartacme.classes.smartacme.js
vendored
File diff suppressed because one or more lines are too long
7
npmextra.json
Normal file
7
npmextra.json
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"npmci": {
|
||||||
|
"globalNpmTools": [
|
||||||
|
"npmts"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "smartacme",
|
"name": "smartacme",
|
||||||
"version": "1.0.3",
|
"version": "1.0.5",
|
||||||
"description": "acme implementation in TypeScript",
|
"description": "acme implementation in TypeScript",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"typings": "dist/index.d.ts",
|
"typings": "dist/index.d.ts",
|
||||||
|
16
test/test.js
16
test/test.js
@ -14,7 +14,7 @@ describe('smartacme', function () {
|
|||||||
should(testAcme.acmeUrl).be.of.type('string');
|
should(testAcme.acmeUrl).be.of.type('string');
|
||||||
});
|
});
|
||||||
it('should register a new account', function (done) {
|
it('should register a new account', function (done) {
|
||||||
this.timeout(40000);
|
this.timeout(10000);
|
||||||
testAcme.createAccount().then(x => {
|
testAcme.createAccount().then(x => {
|
||||||
done();
|
done();
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
@ -22,5 +22,17 @@ describe('smartacme', function () {
|
|||||||
done(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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGVzdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbInRlc3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLHdCQUFxQjtBQUNyQixpQ0FBZ0M7QUFFaEMsNEJBQTRCO0FBQzVCLDJDQUEwQztBQUUxQyxRQUFRLENBQUMsV0FBVyxFQUFFO0lBQ2xCLElBQUksUUFBNkIsQ0FBQTtJQUNqQyxFQUFFLENBQUMsZ0NBQWdDLEVBQUU7UUFDakMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsQ0FBQTtRQUNuQixRQUFRLEdBQUcsSUFBSSxTQUFTLENBQUMsU0FBUyxFQUFFLENBQUE7UUFDcEMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxVQUFVLENBQUMsU0FBUyxDQUFDLFNBQVMsQ0FBQyxDQUFBO0lBQ3ZELENBQUMsQ0FBQyxDQUFBO0lBQ0YsRUFBRSxDQUFDLDZCQUE2QixFQUFFO1FBQzlCLE1BQU0sQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUE7SUFDakQsQ0FBQyxDQUFDLENBQUE7SUFDRixFQUFFLENBQUMsK0JBQStCLEVBQUUsVUFBVSxJQUFJO1FBQzlDLElBQUksQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUE7UUFDbkIsUUFBUSxDQUFDLGFBQWEsRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDO1lBQzNCLElBQUksRUFBRSxDQUFBO1FBQ1YsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLEdBQUc7WUFDUixPQUFPLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFBO1lBQ2hCLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQTtRQUNiLENBQUMsQ0FBQyxDQUFBO0lBQ04sQ0FBQyxDQUFDLENBQUE7QUFDTixDQUFDLENBQUMsQ0FBQSJ9
|
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGVzdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbInRlc3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLHdCQUFxQjtBQUNyQixpQ0FBZ0M7QUFFaEMsNEJBQTRCO0FBQzVCLDJDQUEwQztBQUUxQyxRQUFRLENBQUMsV0FBVyxFQUFFO0lBQ2xCLElBQUksUUFBNkIsQ0FBQTtJQUVqQyxFQUFFLENBQUMsZ0NBQWdDLEVBQUU7UUFDakMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsQ0FBQTtRQUNuQixRQUFRLEdBQUcsSUFBSSxTQUFTLENBQUMsU0FBUyxFQUFFLENBQUE7UUFDcEMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxVQUFVLENBQUMsU0FBUyxDQUFDLFNBQVMsQ0FBQyxDQUFBO0lBQ3ZELENBQUMsQ0FBQyxDQUFBO0lBRUYsRUFBRSxDQUFDLDZCQUE2QixFQUFFO1FBQzlCLE1BQU0sQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUE7SUFDakQsQ0FBQyxDQUFDLENBQUE7SUFFRixFQUFFLENBQUMsK0JBQStCLEVBQUUsVUFBVSxJQUFJO1FBQzlDLElBQUksQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUE7UUFDbkIsUUFBUSxDQUFDLGFBQWEsRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDO1lBQzNCLElBQUksRUFBRSxDQUFBO1FBQ1YsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLEdBQUc7WUFDUixPQUFPLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFBO1lBQ2hCLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQTtRQUNiLENBQUMsQ0FBQyxDQUFBO0lBQ04sQ0FBQyxDQUFDLENBQUE7SUFFRixFQUFFLENBQUMscUJBQXFCLEVBQUUsVUFBUyxJQUFJO1FBQ25DLElBQUksQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUE7UUFDbkIsUUFBUSxDQUFDLFFBQVEsRUFBRSxDQUFDLElBQUksQ0FBQztZQUNyQixJQUFJLEVBQUUsQ0FBQTtRQUNWLENBQUMsQ0FBQyxDQUFBO0lBQ04sQ0FBQyxDQUFDLENBQUE7SUFFRixFQUFFLENBQUMseUNBQXlDLEVBQUUsVUFBUyxJQUFJO1FBQ3ZELElBQUksQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUE7UUFDbkIsUUFBUSxDQUFDLGdCQUFnQixDQUFDLFNBQVMsQ0FBQyxDQUFDLElBQUksQ0FBQztZQUN0QyxJQUFJLEVBQUUsQ0FBQTtRQUNWLENBQUMsQ0FBQyxDQUFBO0lBQ04sQ0FBQyxDQUFDLENBQUE7QUFDTixDQUFDLENBQUMsQ0FBQSJ9
|
19
test/test.ts
19
test/test.ts
@ -6,16 +6,19 @@ import * as smartacme from '../dist/index'
|
|||||||
|
|
||||||
describe('smartacme', function () {
|
describe('smartacme', function () {
|
||||||
let testAcme: smartacme.SmartAcme
|
let testAcme: smartacme.SmartAcme
|
||||||
|
|
||||||
it('should create a valid instance', function () {
|
it('should create a valid instance', function () {
|
||||||
this.timeout(10000)
|
this.timeout(10000)
|
||||||
testAcme = new smartacme.SmartAcme()
|
testAcme = new smartacme.SmartAcme()
|
||||||
should(testAcme).be.instanceOf(smartacme.SmartAcme)
|
should(testAcme).be.instanceOf(smartacme.SmartAcme)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should have created keyPair', function () {
|
it('should have created keyPair', function () {
|
||||||
should(testAcme.acmeUrl).be.of.type('string')
|
should(testAcme.acmeUrl).be.of.type('string')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should register a new account', function (done) {
|
it('should register a new account', function (done) {
|
||||||
this.timeout(40000)
|
this.timeout(10000)
|
||||||
testAcme.createAccount().then(x => {
|
testAcme.createAccount().then(x => {
|
||||||
done()
|
done()
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
@ -23,4 +26,18 @@ describe('smartacme', function () {
|
|||||||
done(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()
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
5
ts/smartacme.classes.acmeaccount.ts
Normal file
5
ts/smartacme.classes.acmeaccount.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import 'typings-global'
|
||||||
|
|
||||||
|
export class AcmeAccount {
|
||||||
|
|
||||||
|
}
|
5
ts/smartacme.classes.acmecert.ts
Normal file
5
ts/smartacme.classes.acmecert.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import 'typings-global'
|
||||||
|
|
||||||
|
export class AcmeCert {
|
||||||
|
|
||||||
|
}
|
@ -1,17 +1,53 @@
|
|||||||
import 'typings-global'
|
import 'typings-global'
|
||||||
|
import * as q from 'q'
|
||||||
let rsaKeygen = require('rsa-keygen')
|
let rsaKeygen = require('rsa-keygen')
|
||||||
|
|
||||||
|
import { SmartAcme } from './smartacme.classes.smartacme'
|
||||||
|
|
||||||
export interface IRsaKeypair {
|
export interface IRsaKeypair {
|
||||||
publicKey: string
|
publicKey: string
|
||||||
privateKey: string
|
privateKey: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export class SmartacmeHelper {
|
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 {
|
createKeypair(bit = 2048): IRsaKeypair {
|
||||||
let result = rsaKeygen.generate(bit)
|
let result = rsaKeygen.generate(bit)
|
||||||
return {
|
return {
|
||||||
publicKey: result.public_key,
|
publicKey: result.public_key,
|
||||||
privateKey: result.private_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
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -9,6 +9,9 @@ import * as paths from './smartacme.paths'
|
|||||||
|
|
||||||
import { SmartacmeHelper, IRsaKeypair } from './smartacme.classes.helper'
|
import { SmartacmeHelper, IRsaKeypair } from './smartacme.classes.helper'
|
||||||
|
|
||||||
|
export type TChallenge = 'dns-01' | 'http-01'
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* class SmartAcme exports methods for maintaining SSL Certificates
|
* class SmartAcme exports methods for maintaining SSL Certificates
|
||||||
*/
|
*/
|
||||||
@ -17,6 +20,9 @@ export class SmartAcme {
|
|||||||
acmeUrl: string // the acme url to use
|
acmeUrl: string // the acme url to use
|
||||||
productionBool: boolean // a boolean to quickly know wether we are in production or not
|
productionBool: boolean // a boolean to quickly know wether we are in production or not
|
||||||
keyPair: IRsaKeypair // the keyPair needed for account creation
|
keyPair: IRsaKeypair // the keyPair needed for account creation
|
||||||
|
location: string
|
||||||
|
link: string
|
||||||
|
rawacmeClient
|
||||||
JWK
|
JWK
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -24,12 +30,12 @@ export class SmartAcme {
|
|||||||
*/
|
*/
|
||||||
constructor(productionArg: boolean = false) {
|
constructor(productionArg: boolean = false) {
|
||||||
this.productionBool = productionArg
|
this.productionBool = productionArg
|
||||||
this.helper = new SmartacmeHelper()
|
this.helper = new SmartacmeHelper(this)
|
||||||
this.keyPair = this.helper.createKeypair()
|
this.keyPair = this.helper.createKeypair()
|
||||||
if (this.productionBool) {
|
if (this.productionBool) {
|
||||||
this.acmeUrl = rawacme.LETSENCRYPT_STAGING_URL
|
|
||||||
} else {
|
|
||||||
this.acmeUrl = rawacme.LETSENCRYPT_URL
|
this.acmeUrl = rawacme.LETSENCRYPT_URL
|
||||||
|
} else {
|
||||||
|
this.acmeUrl = rawacme.LETSENCRYPT_STAGING_URL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,6 +59,10 @@ export class SmartAcme {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// make client available in class
|
||||||
|
this.rawacmeClient = client
|
||||||
|
|
||||||
|
// create the registration
|
||||||
client.newReg(
|
client.newReg(
|
||||||
{
|
{
|
||||||
contact: ['mailto:domains@lossless.org']
|
contact: ['mailto:domains@lossless.org']
|
||||||
@ -65,7 +75,9 @@ export class SmartAcme {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.JWK = res.body.key
|
this.JWK = res.body.key
|
||||||
console.log(this.JWK)
|
this.link = res.headers.link
|
||||||
|
console.log(this.link)
|
||||||
|
this.location = res.headers.location
|
||||||
done.resolve()
|
done.resolve()
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -73,4 +85,94 @@ export class SmartAcme {
|
|||||||
)
|
)
|
||||||
return done.promise
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user