mirror of https://github.com/certd/certd
🔱: [acme] sync upgrade with 3 commits [trident-sync]
Add https-01 challenge test server support Inject CoreDNS into resolv.conf while testing, remove interceptor hackpull/29/head
parent
d22a25d260
commit
18865f0931
|
@ -99,6 +99,10 @@ commands:
|
|||
command: sudo coredns -p 53 -conf /etc/coredns/Corefile
|
||||
background: true
|
||||
|
||||
- run:
|
||||
name: Use CoreDNS in resolv.conf
|
||||
command: echo "nameserver 127.0.0.1" | sudo tee /etc/resolv.conf
|
||||
|
||||
test:
|
||||
steps:
|
||||
- run: yarn --color
|
||||
|
@ -111,7 +115,6 @@ commands:
|
|||
environment:
|
||||
ACME_DOMAIN_NAME: test.example.com
|
||||
ACME_CHALLTESTSRV_URL: http://127.0.0.1:8055
|
||||
ACME_DNS_RESOLVER: 127.0.0.1
|
||||
ACME_TLSALPN_PORT: 5001
|
||||
ACME_HTTP_PORT: 5002
|
||||
ACME_HTTPS_PORT: 5003
|
||||
|
|
|
@ -18,7 +18,7 @@ instance.defaults.headers.common['User-Agent'] = `node-${pkg.name}/${pkg.version
|
|||
/* Default ACME settings */
|
||||
instance.defaults.acmeSettings = {
|
||||
httpChallengePort: 80,
|
||||
bypassCustomDnsResolver: false
|
||||
httpsChallengePort: 443
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -4,15 +4,19 @@
|
|||
|
||||
const dns = require('dns').promises;
|
||||
const { randomUUID: uuid } = require('crypto');
|
||||
const https = require('https');
|
||||
const { assert } = require('chai');
|
||||
const cts = require('./challtestsrv');
|
||||
const axios = require('./../src/axios');
|
||||
|
||||
const domainName = process.env.ACME_DOMAIN_NAME || 'example.com';
|
||||
const httpPort = axios.defaults.acmeSettings.httpChallengePort || 80;
|
||||
const httpsPort = axios.defaults.acmeSettings.httpsChallengePort || 443;
|
||||
|
||||
|
||||
describe('pebble', () => {
|
||||
const httpsAgent = new https.Agent({ rejectUnauthorized: false });
|
||||
|
||||
const testAHost = `${uuid()}.${domainName}`;
|
||||
const testARecords = ['1.1.1.1', '2.2.2.2'];
|
||||
const testCnameHost = `${uuid()}.${domainName}`;
|
||||
|
@ -21,6 +25,11 @@ describe('pebble', () => {
|
|||
const testHttp01ChallengeHost = `${uuid()}.${domainName}`;
|
||||
const testHttp01ChallengeToken = uuid();
|
||||
const testHttp01ChallengeContent = uuid();
|
||||
|
||||
const testHttps01ChallengeHost = `${uuid()}.${domainName}`;
|
||||
const testHttps01ChallengeToken = uuid();
|
||||
const testHttps01ChallengeContent = uuid();
|
||||
|
||||
const testDns01ChallengeHost = `_acme-challenge.${uuid()}.${domainName}.`;
|
||||
const testDns01ChallengeValue = uuid();
|
||||
|
||||
|
@ -79,39 +88,93 @@ describe('pebble', () => {
|
|||
|
||||
|
||||
/**
|
||||
* Challenge response
|
||||
* HTTP-01 challenge response
|
||||
*/
|
||||
|
||||
describe('challenges', () => {
|
||||
it('should not locate http-01 challenge response', async () => {
|
||||
describe('http-01', () => {
|
||||
it('should not locate challenge response', async () => {
|
||||
const resp = await axios.get(`http://${testHttp01ChallengeHost}:${httpPort}/.well-known/acme-challenge/${testHttp01ChallengeToken}`);
|
||||
|
||||
assert.isString(resp.data);
|
||||
assert.notEqual(resp.data, testHttp01ChallengeContent);
|
||||
});
|
||||
|
||||
it('should add http-01 challenge response', async () => {
|
||||
it('should add challenge response', async () => {
|
||||
const resp = await cts.addHttp01ChallengeResponse(testHttp01ChallengeToken, testHttp01ChallengeContent);
|
||||
assert.isTrue(resp);
|
||||
});
|
||||
|
||||
it('should locate http-01 challenge response', async () => {
|
||||
it('should locate challenge response', async () => {
|
||||
const resp = await axios.get(`http://${testHttp01ChallengeHost}:${httpPort}/.well-known/acme-challenge/${testHttp01ChallengeToken}`);
|
||||
|
||||
assert.isString(resp.data);
|
||||
assert.strictEqual(resp.data, testHttp01ChallengeContent);
|
||||
});
|
||||
});
|
||||
|
||||
it('should not locate dns-01 challenge response', async () => {
|
||||
|
||||
/**
|
||||
* HTTPS-01 challenge response
|
||||
*/
|
||||
|
||||
describe('https-01', () => {
|
||||
it('should not locate challenge response', async () => {
|
||||
const r1 = await axios.get(`http://${testHttps01ChallengeHost}:${httpPort}/.well-known/acme-challenge/${testHttps01ChallengeToken}`, { httpsAgent });
|
||||
const r2 = await axios.get(`https://${testHttps01ChallengeHost}:${httpsPort}/.well-known/acme-challenge/${testHttps01ChallengeToken}`, { httpsAgent });
|
||||
|
||||
[r1, r2].forEach((resp) => {
|
||||
assert.isString(resp.data);
|
||||
assert.notEqual(resp.data, testHttps01ChallengeContent);
|
||||
});
|
||||
});
|
||||
|
||||
it('should add challenge response', async () => {
|
||||
const resp = await cts.addHttps01ChallengeResponse(testHttps01ChallengeToken, testHttps01ChallengeContent, testHttps01ChallengeHost, httpsPort);
|
||||
assert.isTrue(resp);
|
||||
});
|
||||
|
||||
it('should 302 with self-signed cert', async () => {
|
||||
/* Assert HTTP 302 */
|
||||
const resp = await axios.get(`http://${testHttps01ChallengeHost}:${httpPort}/.well-known/acme-challenge/${testHttps01ChallengeToken}`, {
|
||||
maxRedirects: 0,
|
||||
validateStatus: null
|
||||
});
|
||||
|
||||
assert.strictEqual(resp.status, 302);
|
||||
assert.strictEqual(resp.headers.location, `https://${testHttps01ChallengeHost}:${httpsPort}/.well-known/acme-challenge/${testHttps01ChallengeToken}`);
|
||||
|
||||
/* Self-signed cert test */
|
||||
await assert.isRejected(axios.get(`https://${testHttps01ChallengeHost}:${httpsPort}/.well-known/acme-challenge/${testHttps01ChallengeToken}`));
|
||||
await assert.isFulfilled(axios.get(`https://${testHttps01ChallengeHost}:${httpsPort}/.well-known/acme-challenge/${testHttps01ChallengeToken}`, { httpsAgent }));
|
||||
});
|
||||
|
||||
it('should locate challenge response', async () => {
|
||||
const r1 = await axios.get(`http://${testHttps01ChallengeHost}:${httpPort}/.well-known/acme-challenge/${testHttps01ChallengeToken}`, { httpsAgent });
|
||||
const r2 = await axios.get(`https://${testHttps01ChallengeHost}:${httpsPort}/.well-known/acme-challenge/${testHttps01ChallengeToken}`, { httpsAgent });
|
||||
|
||||
[r1, r2].forEach((resp) => {
|
||||
assert.isString(resp.data);
|
||||
assert.strictEqual(resp.data, testHttps01ChallengeContent);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* DNS-01 challenge response
|
||||
*/
|
||||
|
||||
describe('dns-01', () => {
|
||||
it('should not locate challenge response', async () => {
|
||||
await assert.isRejected(dns.resolveTxt(testDns01ChallengeHost));
|
||||
});
|
||||
|
||||
it('should add dns-01 challenge response', async () => {
|
||||
it('should add challenge response', async () => {
|
||||
const resp = await cts.addDns01ChallengeResponse(testDns01ChallengeHost, testDns01ChallengeValue);
|
||||
assert.isTrue(resp);
|
||||
});
|
||||
|
||||
it('should locate dns-01 challenge response', async () => {
|
||||
it('should locate challenge response', async () => {
|
||||
const resp = await dns.resolveTxt(testDns01ChallengeHost);
|
||||
|
||||
assert.isArray(resp);
|
||||
|
|
|
@ -26,8 +26,6 @@ describe('http', () => {
|
|||
*/
|
||||
|
||||
before(() => {
|
||||
axios.defaults.acmeSettings.bypassCustomDnsResolver = true;
|
||||
|
||||
const defaultUaOpts = { reqheaders: { 'User-Agent': defaultUserAgent } };
|
||||
const customUaOpts = { reqheaders: { 'User-Agent': customUserAgent } };
|
||||
|
||||
|
@ -43,7 +41,6 @@ describe('http', () => {
|
|||
|
||||
after(() => {
|
||||
axios.defaults.headers.common['User-Agent'] = defaultUserAgent;
|
||||
axios.defaults.acmeSettings.bypassCustomDnsResolver = false;
|
||||
});
|
||||
|
||||
|
||||
|
|
|
@ -50,11 +50,20 @@ async function addHttp01ChallengeResponse(token, content) {
|
|||
return request('add-http01', { token, content });
|
||||
}
|
||||
|
||||
async function addHttps01ChallengeResponse(token, content, targetHostname, targetPort = 443) {
|
||||
await addHttp01ChallengeResponse(token, content);
|
||||
return request('add-redirect', {
|
||||
path: `/.well-known/acme-challenge/${token}`,
|
||||
targetURL: `https://${targetHostname}:${targetPort}/.well-known/acme-challenge/${token}`
|
||||
});
|
||||
}
|
||||
|
||||
async function addDns01ChallengeResponse(host, value) {
|
||||
return request('set-txt', { host, value });
|
||||
}
|
||||
|
||||
exports.addHttp01ChallengeResponse = addHttp01ChallengeResponse;
|
||||
exports.addHttps01ChallengeResponse = addHttps01ChallengeResponse;
|
||||
exports.addDns01ChallengeResponse = addDns01ChallengeResponse;
|
||||
|
||||
|
||||
|
|
|
@ -2,10 +2,7 @@
|
|||
* Setup testing
|
||||
*/
|
||||
|
||||
const url = require('url');
|
||||
const net = require('net');
|
||||
const fs = require('fs');
|
||||
const dns = require('dns').promises;
|
||||
const chai = require('chai');
|
||||
const chaiAsPromised = require('chai-as-promised');
|
||||
const axios = require('./../src/axios');
|
||||
|
@ -19,13 +16,17 @@ chai.use(chaiAsPromised);
|
|||
|
||||
|
||||
/**
|
||||
* HTTP challenge port
|
||||
* Challenge test server ports
|
||||
*/
|
||||
|
||||
if (process.env.ACME_HTTP_PORT) {
|
||||
axios.defaults.acmeSettings.httpChallengePort = process.env.ACME_HTTP_PORT;
|
||||
}
|
||||
|
||||
if (process.env.ACME_HTTPS_PORT) {
|
||||
axios.defaults.acmeSettings.httpsChallengePort = process.env.ACME_HTTPS_PORT;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* External account binding
|
||||
|
@ -38,50 +39,3 @@ if (('ACME_CAP_EAB_ENABLED' in process.env) && (process.env.ACME_CAP_EAB_ENABLED
|
|||
process.env.ACME_EAB_KID = kid;
|
||||
process.env.ACME_EAB_HMAC_KEY = hmacKey;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Custom DNS resolver
|
||||
*/
|
||||
|
||||
if (process.env.ACME_DNS_RESOLVER) {
|
||||
dns.setServers([process.env.ACME_DNS_RESOLVER]);
|
||||
|
||||
|
||||
/**
|
||||
* Axios DNS resolver
|
||||
*/
|
||||
|
||||
axios.interceptors.request.use(async (config) => {
|
||||
const urlObj = url.parse(config.url);
|
||||
|
||||
/* Bypass */
|
||||
if (axios.defaults.acmeSettings.bypassCustomDnsResolver === true) {
|
||||
return config;
|
||||
}
|
||||
|
||||
/* Skip IP addresses and localhost */
|
||||
if (net.isIP(urlObj.hostname) || (urlObj.hostname === 'localhost')) {
|
||||
return config;
|
||||
}
|
||||
|
||||
/* Lookup hostname */
|
||||
const result = await dns.resolve4(urlObj.hostname);
|
||||
|
||||
if (!result.length) {
|
||||
throw new Error(`Unable to lookup address: ${urlObj.hostname}`);
|
||||
}
|
||||
|
||||
/* Place hostname in header */
|
||||
config.headers = config.headers || {};
|
||||
config.headers.Host = urlObj.hostname;
|
||||
|
||||
/* Inject address into URL */
|
||||
delete urlObj.host;
|
||||
urlObj.hostname = result[0];
|
||||
config.url = url.format(urlObj);
|
||||
|
||||
/* Done */
|
||||
return config;
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue