feat(server): add an embedded ACME directory server and certificate authority with challenge, order, and certificate endpoints
This commit is contained in:
61
ts_server/server.classes.challenge.verifier.ts
Normal file
61
ts_server/server.classes.challenge.verifier.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
import * as http from 'node:http';
|
||||
|
||||
/**
|
||||
* Verifies ACME challenges by making HTTP requests or DNS lookups.
|
||||
*/
|
||||
export class ChallengeVerifier {
|
||||
private verificationEnabled: boolean;
|
||||
|
||||
constructor(verificationEnabled = true) {
|
||||
this.verificationEnabled = verificationEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify an HTTP-01 challenge by fetching the token from the domain.
|
||||
*/
|
||||
async verifyHttp01(domain: string, token: string, expectedKeyAuth: string): Promise<boolean> {
|
||||
if (!this.verificationEnabled) {
|
||||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
const url = `http://${domain}/.well-known/acme-challenge/${token}`;
|
||||
const body = await this.httpGet(url);
|
||||
return body.trim() === expectedKeyAuth.trim();
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify a DNS-01 challenge by looking up the TXT record.
|
||||
*/
|
||||
async verifyDns01(domain: string, expectedHash: string): Promise<boolean> {
|
||||
if (!this.verificationEnabled) {
|
||||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
const { promises: dns } = await import('node:dns');
|
||||
const records = await dns.resolveTxt(`_acme-challenge.${domain}`);
|
||||
const flatRecords = records.map((r) => r.join(''));
|
||||
return flatRecords.some((r) => r === expectedHash);
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private httpGet(url: string): Promise<string> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const req = http.get(url, { timeout: 10000 }, (res) => {
|
||||
const chunks: Buffer[] = [];
|
||||
res.on('data', (chunk: Buffer) => chunks.push(chunk));
|
||||
res.on('end', () => resolve(Buffer.concat(chunks).toString('utf-8')));
|
||||
});
|
||||
req.on('error', reject);
|
||||
req.on('timeout', () => {
|
||||
req.destroy(new Error('HTTP-01 verification timeout'));
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user