-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlib.js
executable file
·105 lines (98 loc) · 4.18 KB
/
lib.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
'use strict';
const Promise = require('bluebird');
const LeTinyCore = require('letiny-core');
const LeCore = Promise.promisifyAll(LeTinyCore);
const LeCrypto = Promise.promisifyAll(LeCore.leCrypto);
const ms = require('ms');
const request = require('request-promise');
const getUrls = LeCore.getAcmeUrlsAsync(LeCore.productionServerUrl);
const generateRsa = () => LeCrypto.generateRsaKeypairAsync(2048, 65537);
const pollUntilDeployed = (url, expectedContent, timeoutMs = 15 * 1000, retries = 10) => {
if (retries > 0) {
return request.get({
url: url,
simple: false // don't reject on 404
}).then(res => {
if (res === expectedContent) {
return Promise.resolve();
} else {
console.log(`Could not find challenge file. Retrying in ${ms(timeoutMs)}...`);
return Promise.delay(timeoutMs).then(() =>
pollUntilDeployed(url, expectedContent, timeoutMs * 2, retries - 1));
}
});
} else {
return Promise.reject(`Timed out while waiting for challenge file at ${url}`);
}
};
module.exports = (options) => {
const gitlabRequest = request.defaults({
headers: { 'PRIVATE-TOKEN': options.token },
json: true,
baseUrl: 'https://gitlab.com/api/v3'
});
const getRepository = (name) => {
return gitlabRequest.get({
url: `/projects/${name.replace('/','%2F')}`
});
};
const uploadChallenge = (key, value, repo, domain) => {
var file_path = 'source/_static/.well-known/acme-challenge/';
if(typeof options.path != 'undefined' && options.path.length > 0){
file_path = options.path;
}
// Need to bluebird-ify to use .asCallback()
return Promise.resolve(gitlabRequest.post({
url: `/projects/${repo.id}/repository/files`,
body: {
file_path: `${file_path}${key}`,
commit_message: 'Automated Let\'s Encrypt renewal',
branch_name: 'master',
content: value
}
})).return([`http://${domain}/.well-known/acme-challenge/${key}`, value]);
};
const deleteChallenges = (key, repo) => {
var file_path = 'source/_static/.well-known/acme-challenge/';
if(typeof options.path != 'undefined' && options.path.length > 0){
file_path = options.path;
}
return Promise.resolve(gitlabRequest.delete({
url: `projects/${repo.id}/repository/files`,
body: {
file_path: `${file_path}${key}`,
commit_message: 'Automated Let\'s Encrypt renewal',
branch_name: 'master'
}
}));
};
return Promise.join(getUrls, generateRsa(), generateRsa(), getRepository(options.repository),
(urls, accountKp, domainKp, repo) => {
return LeCore.registerNewAccountAsync({
newRegUrl: urls.newReg,
email: options.email,
accountPrivateKeyPem: accountKp.privateKeyPem,
agreeToTerms: (tosUrl, cb) => {
console.log(`By using Let's Encrypt, you are agreeing to the TOS at ${tosUrl}`);
cb(null, true);
}
}).then(() => {
return LeCore.getCertificateAsync({
newAuthzUrl: urls.newAuthz,
newCertUrl: urls.newCert,
domainPrivateKeyPem: domainKp.privateKeyPem,
accountPrivateKeyPem: accountKp.privateKeyPem,
domains: [options.domain],
setChallenge: (hostname, key, value, cb) => {
return uploadChallenge(key, value, repo, options.domain)
.tap(res => console.log(`Uploaded challenge file, waiting for it to be available at ${res[0]}`))
.spread(pollUntilDeployed)
.asCallback(cb);
},
removeChallenge: (hostname, key, cb) => {
return deleteChallenges(key, repo).asCallback(cb);
}
});
});
});
};