Skip to content

Commit bfbe47c

Browse files
authored
fix: incorporate greenlock files into redbird (#295)
1 parent bde77bc commit bfbe47c

File tree

6 files changed

+594
-736
lines changed

6 files changed

+594
-736
lines changed

bun.lockb

776 Bytes
Binary file not shown.

lib/letsencrypt.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import url from 'url';
1111
import fs from 'fs';
1212
import pino from 'pino';
1313

14+
import leChallengeFs from './third-party/le-challenge-fs.js';
15+
1416
/**
1517
* LetsEncrypt certificates are stored like the following:
1618
*
@@ -88,10 +90,10 @@ async function getCertificates(
8890
let le;
8991

9092
// Storage Backend
91-
var leStore = (await import('le-store-certbot')).create(leStoreConfig);
93+
const leStore = require('le-store-certbot').create(leStoreConfig);
9294

9395
// ACME Challenge Handlers
94-
var leChallenge = (await import('le-challenge-fs')).create({
96+
const leChallenge = leChallengeFs.create({
9597
webrootPath,
9698
debug: false,
9799
});

lib/third-party/le-challenge-fs.ts

+172
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
'use strict';
2+
3+
/*
4+
Original code License:
5+
6+
acme-http-01-webroot.js | MPL-2.0 | Terms of Use | Privacy Policy
7+
Copyright 2019 AJ ONeal Copyright 2019 The Root Group LLC
8+
9+
https://git.rootprojects.org/root/acme-http-01-webroot.js.git
10+
*/
11+
12+
import fs from 'fs';
13+
import { IncomingMessage } from 'http';
14+
import path from 'path';
15+
import os from 'os';
16+
import http from 'http';
17+
import { mkdirp } from 'mkdirp';
18+
19+
const myDefaults = {
20+
//webrootPath: [ '~', 'letsencrypt', 'const', 'lib' ].join(path.sep)
21+
webrootPath: path.join(os.tmpdir(), 'acme-challenge'),
22+
loopbackTimeout: 5 * 1000,
23+
debug: false,
24+
};
25+
26+
const Challenge = {
27+
create: function (options: any) {
28+
const results: any = {};
29+
30+
Object.keys(Challenge).forEach(function (key: string) {
31+
results[key] = (<any>Challenge)[key];
32+
});
33+
results.create = undefined;
34+
35+
Object.keys(myDefaults).forEach(function (key) {
36+
if ('undefined' === typeof options[key]) {
37+
options[key] = (<any>myDefaults)[key];
38+
}
39+
});
40+
results._options = options;
41+
42+
results.getOptions = function () {
43+
return results._options;
44+
};
45+
46+
return results;
47+
},
48+
49+
//
50+
// NOTE: the "args" here in `set()` are NOT accessible to `get()` and `remove()`
51+
// They are provided so that you can store them in an implementation-specific way
52+
// if you need access to them.
53+
set: function (
54+
args: any,
55+
domain: string,
56+
challengePath: string,
57+
keyAuthorization: any,
58+
done: (err?: NodeJS.ErrnoException) => void
59+
) {
60+
keyAuthorization = String(keyAuthorization);
61+
62+
mkdirp(args.webrootPath)
63+
.then(function (): void {
64+
fs.writeFile(
65+
path.join(args.webrootPath, challengePath),
66+
keyAuthorization,
67+
'utf8',
68+
function (err: NodeJS.ErrnoException) {
69+
done(err);
70+
}
71+
);
72+
})
73+
.catch((err) => {
74+
if (err) {
75+
done(err);
76+
return;
77+
}
78+
});
79+
},
80+
81+
//
82+
// NOTE: the "defaults" here are still merged and templated, just like "args" would be,
83+
// but if you specifically need "args" you must retrieve them from some storage mechanism
84+
// based on domain and key
85+
//
86+
get: function (defaults: any, domain: string, key: string, done: () => void) {
87+
fs.readFile(path.join(defaults.webrootPath, key), 'utf8', done);
88+
},
89+
90+
remove: function (defaults: any, domain: string, key: string, done: () => void) {
91+
fs.unlink(path.join(defaults.webrootPath, key), done);
92+
},
93+
94+
loopback: function (
95+
defaults: any,
96+
domain: string,
97+
key: string,
98+
done: (err?: NodeJS.ErrnoException, value?: any) => void
99+
) {
100+
const hostname = domain + (defaults.loopbackPort ? ':' + defaults.loopbackPort : '');
101+
const urlstr = 'http://' + hostname + '/.well-known/acme-challenge/' + key;
102+
103+
http
104+
.get(urlstr, function (res: IncomingMessage) {
105+
if (200 !== res.statusCode) {
106+
done(new Error('local loopback failed with statusCode ' + res.statusCode));
107+
return;
108+
}
109+
const chunks: any[] = [];
110+
res.on('data', function (chunk) {
111+
chunks.push(chunk);
112+
});
113+
res.on('end', function () {
114+
const str = Buffer.concat(chunks).toString('utf8').trim();
115+
done(null, str);
116+
});
117+
})
118+
.setTimeout(defaults.loopbackTimeout, function () {
119+
done(new Error('loopback timeout, could not reach server'));
120+
})
121+
.on('error', function (err: NodeJS.ErrnoException) {
122+
done(err);
123+
});
124+
},
125+
126+
/*
127+
test: function (
128+
args: any,
129+
domain: string,
130+
challenge: any,
131+
keyAuthorization: any,
132+
done: (err?: NodeJS.ErrnoException) => void
133+
) {
134+
const me = this;
135+
const key = keyAuthorization || challenge;
136+
137+
me.set(args, domain, challenge, key, function (err) {
138+
if (err) {
139+
done(err);
140+
return;
141+
}
142+
143+
myDefaults.loopbackPort = args.loopbackPort;
144+
myDefaults.webrootPath = args.webrootPath;
145+
me.loopback(args, domain, challenge, function (err, _key) {
146+
if (err) {
147+
done(err);
148+
return;
149+
}
150+
151+
if (key !== _key) {
152+
err = new Error(
153+
"keyAuthorization [original] '" + key + "'" + " did not match [result] '" + _key + "'"
154+
);
155+
return;
156+
}
157+
158+
me.remove(myDefaults, domain, challenge, function (_err) {
159+
if (_err) {
160+
done(_err);
161+
return;
162+
}
163+
164+
done(err);
165+
});
166+
});
167+
});
168+
},
169+
*/
170+
};
171+
172+
export default Challenge;

0 commit comments

Comments
 (0)