BREAKING CHANGE(smartacme): Make wildcard certificates opt-in to fix HTTP-01 only configurations
This commit is contained in:
parent
dcc89f0088
commit
086eea1aa2
17
changelog.md
17
changelog.md
@ -1,5 +1,22 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 2025-05-19 - 8.0.0 - BREAKING CHANGE(smartacme)
|
||||||
|
Make wildcard certificates opt-in to fix HTTP-01 only configurations
|
||||||
|
|
||||||
|
- BREAKING CHANGE: Wildcard certificates are no longer automatically requested for all domains
|
||||||
|
- Added 'includeWildcard' option to getCertificateForDomain() to explicitly request wildcard certificates
|
||||||
|
- HTTP-01 only configurations now work correctly as they do not try to request wildcard certificates automatically
|
||||||
|
- Updated certificate CSR generation to match the requested domain configuration
|
||||||
|
|
||||||
|
## 2025-05-19 - 7.4.0 - feat(smartacme)
|
||||||
|
Make wildcard certificates opt-in to fix HTTP-01 only configurations
|
||||||
|
|
||||||
|
- BREAKING CHANGE: Wildcard certificates are no longer automatically requested for all domains
|
||||||
|
- Added `includeWildcard` option to `getCertificateForDomain()` to explicitly request wildcards
|
||||||
|
- HTTP-01 only configurations now work correctly as they no longer attempt wildcard certificates
|
||||||
|
- Wildcard certificates require DNS-01 handler and must be explicitly requested
|
||||||
|
- Updated certificate CSR generation to match the requested domain configuration
|
||||||
|
|
||||||
## 2025-05-18 - 7.3.4 - fix(smartacme)
|
## 2025-05-18 - 7.3.4 - fix(smartacme)
|
||||||
Refine documentation and tests for improved clarity in ACME certificate management
|
Refine documentation and tests for improved clarity in ACME certificate management
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@push.rocks/smartacme",
|
"name": "@push.rocks/smartacme",
|
||||||
"version": "7.3.4",
|
"version": "7.4.0",
|
||||||
"private": false,
|
"private": false,
|
||||||
"description": "A TypeScript-based ACME client for LetsEncrypt certificate management with a focus on simplicity and power.",
|
"description": "A TypeScript-based ACME client for LetsEncrypt certificate management with a focus on simplicity and power.",
|
||||||
"main": "dist_ts/index.js",
|
"main": "dist_ts/index.js",
|
||||||
|
@ -1,2 +1,13 @@
|
|||||||
- this repo is dependent on letsencrypt and its limits
|
- this repo is dependent on letsencrypt and its limits
|
||||||
- to simpify the outside API, smartacme is stateful, meaning it works with a mongodb and a collection called 'SmartacmeCert'.
|
- to simpify the outside API, smartacme is stateful, meaning it works with a mongodb and a collection called 'SmartacmeCert'.
|
||||||
|
|
||||||
|
## Certificate Request Behavior
|
||||||
|
|
||||||
|
As of v7.4.0, SmartAcme no longer automatically requests wildcard certificates for all domain requests. This change was made to fix issues with HTTP-01 only configurations which cannot validate wildcard domains.
|
||||||
|
|
||||||
|
- By default, `getCertificateForDomain('example.com')` only requests a certificate for `example.com`
|
||||||
|
- To request both regular and wildcard certificates, use `getCertificateForDomain('example.com', { includeWildcard: true })`
|
||||||
|
- Wildcard certificates require a DNS-01 challenge handler to be configured
|
||||||
|
- Direct wildcard requests like `getCertificateForDomain('*.example.com')` only request the wildcard certificate
|
||||||
|
|
||||||
|
This change ensures HTTP-01 only configurations work properly while still allowing wildcard certificates when needed and supported.
|
10
readme.md
10
readme.md
@ -196,8 +196,13 @@ async function main() {
|
|||||||
await smartAcmeInstance.start();
|
await smartAcmeInstance.start();
|
||||||
|
|
||||||
const myDomain = 'example.com';
|
const myDomain = 'example.com';
|
||||||
|
// Get certificate for domain (no wildcard)
|
||||||
const myCert = await smartAcmeInstance.getCertificateForDomain(myDomain);
|
const myCert = await smartAcmeInstance.getCertificateForDomain(myDomain);
|
||||||
console.log('Certificate:', myCert);
|
console.log('Certificate:', myCert);
|
||||||
|
|
||||||
|
// Get certificate with wildcard (requires DNS-01 handler)
|
||||||
|
const certWithWildcard = await smartAcmeInstance.getCertificateForDomain(myDomain, { includeWildcard: true });
|
||||||
|
console.log('Certificate with wildcard:', certWithWildcard);
|
||||||
|
|
||||||
await smartAcmeInstance.stop();
|
await smartAcmeInstance.stop();
|
||||||
}
|
}
|
||||||
@ -306,7 +311,10 @@ The certificate object obtained from the `getCertificateForDomain` method has th
|
|||||||
|
|
||||||
- **start()**: Initializes the SmartAcme instance, sets up the ACME client, and registers the account with Let's Encrypt.
|
- **start()**: Initializes the SmartAcme instance, sets up the ACME client, and registers the account with Let's Encrypt.
|
||||||
- **stop()**: Closes the MongoDB connection and performs any necessary cleanup.
|
- **stop()**: Closes the MongoDB connection and performs any necessary cleanup.
|
||||||
- **getCertificateForDomain(domainArg: string)**: Retrieves or obtains a certificate for the specified domain name. If a valid certificate exists in the database, it is returned. Otherwise, a new certificate is requested and stored.
|
- **getCertificateForDomain(domainArg: string, options?: { includeWildcard?: boolean })**: Retrieves or obtains a certificate for the specified domain name. If a valid certificate exists in the database, it is returned. Otherwise, a new certificate is requested and stored.
|
||||||
|
- By default, only a certificate for the exact domain is requested
|
||||||
|
- Set `includeWildcard: true` to also request a wildcard certificate (requires DNS-01 handler)
|
||||||
|
- When requesting a wildcard directly (e.g., `*.example.com`), only the wildcard certificate is requested
|
||||||
|
|
||||||
### Handling Domain Matching
|
### Handling Domain Matching
|
||||||
|
|
||||||
|
178
test/test.http01-only.ts
Normal file
178
test/test.http01-only.ts
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
import { tap, expect } from '@push.rocks/tapbundle';
|
||||||
|
import { SmartAcme, certmanagers } from '../ts/index.js';
|
||||||
|
import { Http01MemoryHandler } from '../ts/handlers/Http01MemoryHandler.js';
|
||||||
|
|
||||||
|
// Test that HTTP-01 only configuration works without wildcard certificates
|
||||||
|
tap.test('HTTP-01 only configuration should work for regular domains', async () => {
|
||||||
|
const memHandler = new Http01MemoryHandler();
|
||||||
|
|
||||||
|
// Stub the domain support check to always return true for testing
|
||||||
|
memHandler.checkWetherDomainIsSupported = async () => true;
|
||||||
|
|
||||||
|
const smartAcmeInstance = new SmartAcme({
|
||||||
|
accountEmail: 'test@example.com',
|
||||||
|
certManager: new certmanagers.MemoryCertManager(),
|
||||||
|
environment: 'integration',
|
||||||
|
retryOptions: {},
|
||||||
|
challengeHandlers: [memHandler],
|
||||||
|
challengePriority: ['http-01'],
|
||||||
|
});
|
||||||
|
|
||||||
|
// Stub the start method to avoid actual ACME connections
|
||||||
|
smartAcmeInstance.start = async () => {
|
||||||
|
smartAcmeInstance.certmatcher = {
|
||||||
|
getCertificateDomainNameByDomainName: (domain: string) => domain.replace('*.', '')
|
||||||
|
} as any;
|
||||||
|
smartAcmeInstance.interestMap = {
|
||||||
|
checkInterest: async () => false,
|
||||||
|
addInterest: async () => ({ interestFullfilled: new Promise(() => {}) } as any)
|
||||||
|
} as any;
|
||||||
|
await smartAcmeInstance.certmanager.init();
|
||||||
|
};
|
||||||
|
await smartAcmeInstance.start();
|
||||||
|
|
||||||
|
// Stub the core certificate methods to avoid actual ACME calls
|
||||||
|
smartAcmeInstance.client = {
|
||||||
|
createOrder: async (orderPayload: any) => {
|
||||||
|
// Verify no wildcard is included in default request
|
||||||
|
const identifiers = orderPayload.identifiers;
|
||||||
|
expect(identifiers.length).toEqual(1);
|
||||||
|
expect(identifiers[0].value).toEqual('example.com');
|
||||||
|
expect(identifiers.find((id: any) => id.value.startsWith('*.'))).toBeUndefined();
|
||||||
|
return { status: 'pending', authorizations: [], finalize: '', certificate: '' };
|
||||||
|
},
|
||||||
|
getAuthorizations: async () => [],
|
||||||
|
finalizeOrder: async () => {},
|
||||||
|
getCertificate: async () => '-----BEGIN CERTIFICATE-----\ntest\n-----END CERTIFICATE-----',
|
||||||
|
} as any;
|
||||||
|
|
||||||
|
smartAcmeInstance.retry = async (fn: () => Promise<any>) => fn();
|
||||||
|
|
||||||
|
// Mock certmanager methods
|
||||||
|
smartAcmeInstance.certmanager.retrieveCertificate = async () => null;
|
||||||
|
smartAcmeInstance.certmanager.storeCertificate = async (cert: any) => cert;
|
||||||
|
|
||||||
|
// Request certificate without wildcard
|
||||||
|
const cert = await smartAcmeInstance.getCertificateForDomain('example.com');
|
||||||
|
expect(cert).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
tap.test('should only include wildcard when explicitly requested with DNS-01', async () => {
|
||||||
|
const dnsHandler = {
|
||||||
|
getSupportedTypes: () => ['dns-01'],
|
||||||
|
prepare: async () => {},
|
||||||
|
cleanup: async () => {},
|
||||||
|
checkWetherDomainIsSupported: async () => true,
|
||||||
|
};
|
||||||
|
|
||||||
|
const smartAcmeInstance = new SmartAcme({
|
||||||
|
accountEmail: 'test@example.com',
|
||||||
|
certManager: new certmanagers.MemoryCertManager(),
|
||||||
|
environment: 'integration',
|
||||||
|
retryOptions: {},
|
||||||
|
challengeHandlers: [dnsHandler],
|
||||||
|
challengePriority: ['dns-01'],
|
||||||
|
});
|
||||||
|
|
||||||
|
// Stub the start method to avoid actual ACME connections
|
||||||
|
smartAcmeInstance.start = async () => {
|
||||||
|
smartAcmeInstance.certmatcher = {
|
||||||
|
getCertificateDomainNameByDomainName: (domain: string) => domain.replace('*.', '')
|
||||||
|
} as any;
|
||||||
|
smartAcmeInstance.interestMap = {
|
||||||
|
checkInterest: async () => false,
|
||||||
|
addInterest: async () => ({ interestFullfilled: new Promise(() => {}) } as any)
|
||||||
|
} as any;
|
||||||
|
await smartAcmeInstance.certmanager.init();
|
||||||
|
};
|
||||||
|
await smartAcmeInstance.start();
|
||||||
|
|
||||||
|
// Stub the core certificate methods
|
||||||
|
smartAcmeInstance.client = {
|
||||||
|
createOrder: async (orderPayload: any) => {
|
||||||
|
const identifiers = orderPayload.identifiers;
|
||||||
|
expect(identifiers.length).toEqual(2);
|
||||||
|
expect(identifiers[0].value).toEqual('example.com');
|
||||||
|
expect(identifiers[1].value).toEqual('*.example.com');
|
||||||
|
return { status: 'pending', authorizations: [], finalize: '', certificate: '' };
|
||||||
|
},
|
||||||
|
getAuthorizations: async () => [],
|
||||||
|
finalizeOrder: async () => {},
|
||||||
|
getCertificate: async () => '-----BEGIN CERTIFICATE-----\ntest\n-----END CERTIFICATE-----',
|
||||||
|
} as any;
|
||||||
|
|
||||||
|
smartAcmeInstance.retry = async (fn: () => Promise<any>) => fn();
|
||||||
|
|
||||||
|
// Mock certmanager methods
|
||||||
|
smartAcmeInstance.certmanager.retrieveCertificate = async () => null;
|
||||||
|
smartAcmeInstance.certmanager.storeCertificate = async (cert: any) => cert;
|
||||||
|
|
||||||
|
// Request certificate with wildcard
|
||||||
|
const cert = await smartAcmeInstance.getCertificateForDomain('example.com', { includeWildcard: true });
|
||||||
|
expect(cert).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
tap.test('should skip wildcard if requested but no DNS-01 handler available', async () => {
|
||||||
|
const httpHandler = new Http01MemoryHandler();
|
||||||
|
httpHandler.checkWetherDomainIsSupported = async () => true;
|
||||||
|
|
||||||
|
const smartAcmeInstance = new SmartAcme({
|
||||||
|
accountEmail: 'test@example.com',
|
||||||
|
certManager: new certmanagers.MemoryCertManager(),
|
||||||
|
environment: 'integration',
|
||||||
|
retryOptions: {},
|
||||||
|
challengeHandlers: [httpHandler],
|
||||||
|
challengePriority: ['http-01'],
|
||||||
|
});
|
||||||
|
|
||||||
|
// Stub the start method to avoid actual ACME connections
|
||||||
|
smartAcmeInstance.start = async () => {
|
||||||
|
smartAcmeInstance.certmatcher = {
|
||||||
|
getCertificateDomainNameByDomainName: (domain: string) => domain.replace('*.', '')
|
||||||
|
} as any;
|
||||||
|
smartAcmeInstance.interestMap = {
|
||||||
|
checkInterest: async () => false,
|
||||||
|
addInterest: async () => ({ interestFullfilled: new Promise(() => {}) } as any)
|
||||||
|
} as any;
|
||||||
|
await smartAcmeInstance.certmanager.init();
|
||||||
|
};
|
||||||
|
await smartAcmeInstance.start();
|
||||||
|
|
||||||
|
// Mock logger to capture warning
|
||||||
|
const logSpy = { called: false, message: '' };
|
||||||
|
smartAcmeInstance.logger.log = async (level: string, message: string) => {
|
||||||
|
if (level === 'warn') {
|
||||||
|
logSpy.called = true;
|
||||||
|
logSpy.message = message;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Stub the core certificate methods
|
||||||
|
smartAcmeInstance.client = {
|
||||||
|
createOrder: async (orderPayload: any) => {
|
||||||
|
const identifiers = orderPayload.identifiers;
|
||||||
|
// Should only have regular domain, no wildcard
|
||||||
|
expect(identifiers.length).toEqual(1);
|
||||||
|
expect(identifiers[0].value).toEqual('example.com');
|
||||||
|
return { status: 'pending', authorizations: [], finalize: '', certificate: '' };
|
||||||
|
},
|
||||||
|
getAuthorizations: async () => [],
|
||||||
|
finalizeOrder: async () => {},
|
||||||
|
getCertificate: async () => '-----BEGIN CERTIFICATE-----\ntest\n-----END CERTIFICATE-----',
|
||||||
|
} as any;
|
||||||
|
|
||||||
|
smartAcmeInstance.retry = async (fn: () => Promise<any>) => fn();
|
||||||
|
|
||||||
|
// Mock certmanager methods
|
||||||
|
smartAcmeInstance.certmanager.retrieveCertificate = async () => null;
|
||||||
|
smartAcmeInstance.certmanager.storeCertificate = async (cert: any) => cert;
|
||||||
|
|
||||||
|
// Request certificate with wildcard (should be skipped)
|
||||||
|
const cert = await smartAcmeInstance.getCertificateForDomain('example.com', { includeWildcard: true });
|
||||||
|
|
||||||
|
expect(cert).toBeDefined();
|
||||||
|
expect(logSpy.called).toBeTrue();
|
||||||
|
expect(logSpy.message).toContain('Wildcard certificate requested but no DNS-01 handler available');
|
||||||
|
});
|
||||||
|
|
||||||
|
export default tap.start();
|
94
test/test.wildcard-options.ts
Normal file
94
test/test.wildcard-options.ts
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
import { tap, expect } from '@push.rocks/tapbundle';
|
||||||
|
import { SmartAcme, certmanagers } from '../ts/index.js';
|
||||||
|
import { SmartacmeCert as Cert } from '../ts/smartacme.classes.cert.js';
|
||||||
|
|
||||||
|
// Simple test to verify wildcard options are correctly processed
|
||||||
|
tap.test('should not include wildcard by default for regular domain', async () => {
|
||||||
|
let orderPayload: any = null;
|
||||||
|
|
||||||
|
// Override the SmartAcme prototype methods for testing
|
||||||
|
const origGetCert = SmartAcme.prototype.getCertificateForDomain;
|
||||||
|
|
||||||
|
// Create a minimal test version of getCertificateForDomain
|
||||||
|
SmartAcme.prototype.getCertificateForDomain = async function(
|
||||||
|
domainArg: string,
|
||||||
|
options?: { includeWildcard?: boolean }
|
||||||
|
) {
|
||||||
|
const certDomainName = domainArg.replace('*.', '');
|
||||||
|
const identifiers = [];
|
||||||
|
|
||||||
|
if (domainArg.startsWith('*.')) {
|
||||||
|
identifiers.push({ type: 'dns', value: domainArg });
|
||||||
|
} else {
|
||||||
|
identifiers.push({ type: 'dns', value: certDomainName });
|
||||||
|
|
||||||
|
if (options?.includeWildcard) {
|
||||||
|
const hasDnsHandler = this.challengeHandlers.some((h) =>
|
||||||
|
h.getSupportedTypes().includes('dns-01')
|
||||||
|
);
|
||||||
|
|
||||||
|
if (hasDnsHandler) {
|
||||||
|
identifiers.push({ type: 'dns', value: `*.${certDomainName}` });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
orderPayload = { identifiers };
|
||||||
|
return new Cert({ domainName: certDomainName });
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Create instance with HTTP-01 only
|
||||||
|
const smartAcme = new SmartAcme({
|
||||||
|
accountEmail: 'test@example.com',
|
||||||
|
certManager: new certmanagers.MemoryCertManager(),
|
||||||
|
environment: 'integration',
|
||||||
|
challengeHandlers: [{
|
||||||
|
getSupportedTypes: () => ['http-01'],
|
||||||
|
prepare: async () => {},
|
||||||
|
cleanup: async () => {},
|
||||||
|
checkWetherDomainIsSupported: async () => true,
|
||||||
|
}],
|
||||||
|
});
|
||||||
|
|
||||||
|
// Test 1: Regular domain without wildcard option
|
||||||
|
await smartAcme.getCertificateForDomain('example.com');
|
||||||
|
expect(orderPayload.identifiers.length).toEqual(1);
|
||||||
|
expect(orderPayload.identifiers[0].value).toEqual('example.com');
|
||||||
|
|
||||||
|
// Test 2: Regular domain with wildcard option (but no DNS-01 handler)
|
||||||
|
await smartAcme.getCertificateForDomain('example.com', { includeWildcard: true });
|
||||||
|
expect(orderPayload.identifiers.length).toEqual(1);
|
||||||
|
expect(orderPayload.identifiers[0].value).toEqual('example.com');
|
||||||
|
|
||||||
|
// Create instance with DNS-01
|
||||||
|
const smartAcmeDns = new SmartAcme({
|
||||||
|
accountEmail: 'test@example.com',
|
||||||
|
certManager: new certmanagers.MemoryCertManager(),
|
||||||
|
environment: 'integration',
|
||||||
|
challengeHandlers: [{
|
||||||
|
getSupportedTypes: () => ['dns-01'],
|
||||||
|
prepare: async () => {},
|
||||||
|
cleanup: async () => {},
|
||||||
|
checkWetherDomainIsSupported: async () => true,
|
||||||
|
}],
|
||||||
|
});
|
||||||
|
|
||||||
|
// Test 3: Regular domain with wildcard option and DNS-01 handler
|
||||||
|
await smartAcmeDns.getCertificateForDomain('example.com', { includeWildcard: true });
|
||||||
|
expect(orderPayload.identifiers.length).toEqual(2);
|
||||||
|
expect(orderPayload.identifiers[0].value).toEqual('example.com');
|
||||||
|
expect(orderPayload.identifiers[1].value).toEqual('*.example.com');
|
||||||
|
|
||||||
|
// Test 4: Direct wildcard request
|
||||||
|
await smartAcmeDns.getCertificateForDomain('*.example.com');
|
||||||
|
expect(orderPayload.identifiers.length).toEqual(1);
|
||||||
|
expect(orderPayload.identifiers[0].value).toEqual('*.example.com');
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
// Restore original method
|
||||||
|
SmartAcme.prototype.getCertificateForDomain = origGetCert;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default tap.start();
|
@ -3,6 +3,6 @@
|
|||||||
*/
|
*/
|
||||||
export const commitinfo = {
|
export const commitinfo = {
|
||||||
name: '@push.rocks/smartacme',
|
name: '@push.rocks/smartacme',
|
||||||
version: '7.3.4',
|
version: '8.0.0',
|
||||||
description: 'A TypeScript-based ACME client for LetsEncrypt certificate management with a focus on simplicity and power.'
|
description: 'A TypeScript-based ACME client for LetsEncrypt certificate management with a focus on simplicity and power.'
|
||||||
}
|
}
|
||||||
|
@ -221,8 +221,12 @@ export class SmartAcme {
|
|||||||
* * retrieve it from the databse and return it
|
* * retrieve it from the databse and return it
|
||||||
*
|
*
|
||||||
* @param domainArg
|
* @param domainArg
|
||||||
|
* @param options Optional configuration for certificate generation
|
||||||
*/
|
*/
|
||||||
public async getCertificateForDomain(domainArg: string): Promise<SmartacmeCert> {
|
public async getCertificateForDomain(
|
||||||
|
domainArg: string,
|
||||||
|
options?: { includeWildcard?: boolean }
|
||||||
|
): Promise<SmartacmeCert> {
|
||||||
// Determine if this is a wildcard request (e.g., '*.example.com').
|
// Determine if this is a wildcard request (e.g., '*.example.com').
|
||||||
const isWildcardRequest = domainArg.startsWith('*.');
|
const isWildcardRequest = domainArg.startsWith('*.');
|
||||||
// Determine the base domain for certificate retrieval/issuance.
|
// Determine the base domain for certificate retrieval/issuance.
|
||||||
@ -259,12 +263,32 @@ export class SmartAcme {
|
|||||||
// lets make sure others get the same interest
|
// lets make sure others get the same interest
|
||||||
const currentDomainInterst = await this.interestMap.addInterest(certDomainName);
|
const currentDomainInterst = await this.interestMap.addInterest(certDomainName);
|
||||||
|
|
||||||
|
// Build identifiers array based on request
|
||||||
|
const identifiers = [];
|
||||||
|
|
||||||
|
if (isWildcardRequest) {
|
||||||
|
// If requesting a wildcard directly, only add the wildcard
|
||||||
|
identifiers.push({ type: 'dns', value: `*.${certDomainName}` });
|
||||||
|
} else {
|
||||||
|
// Add the regular domain
|
||||||
|
identifiers.push({ type: 'dns', value: certDomainName });
|
||||||
|
|
||||||
|
// Only add wildcard if explicitly requested
|
||||||
|
if (options?.includeWildcard) {
|
||||||
|
const hasDnsHandler = this.challengeHandlers.some((h) =>
|
||||||
|
h.getSupportedTypes().includes('dns-01'),
|
||||||
|
);
|
||||||
|
if (!hasDnsHandler) {
|
||||||
|
this.logger.log('warn', 'Wildcard certificate requested but no DNS-01 handler available. Skipping wildcard.');
|
||||||
|
} else {
|
||||||
|
identifiers.push({ type: 'dns', value: `*.${certDomainName}` });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Place new order with retry */
|
/* Place new order with retry */
|
||||||
const order = await this.retry(() => this.client.createOrder({
|
const order = await this.retry(() => this.client.createOrder({
|
||||||
identifiers: [
|
identifiers,
|
||||||
{ type: 'dns', value: certDomainName },
|
|
||||||
{ type: 'dns', value: `*.${certDomainName}` },
|
|
||||||
],
|
|
||||||
}), 'createOrder');
|
}), 'createOrder');
|
||||||
|
|
||||||
/* Get authorizations and select challenges */
|
/* Get authorizations and select challenges */
|
||||||
@ -359,9 +383,25 @@ export class SmartAcme {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Finalize order */
|
/* Finalize order */
|
||||||
|
const csrDomains = [];
|
||||||
|
let commonName: string;
|
||||||
|
|
||||||
|
if (isWildcardRequest) {
|
||||||
|
// For wildcard requests, use wildcard as common name
|
||||||
|
commonName = `*.${certDomainName}`;
|
||||||
|
csrDomains.push(certDomainName); // Add base domain as alt name
|
||||||
|
} else {
|
||||||
|
// For regular requests, use base domain as common name
|
||||||
|
commonName = certDomainName;
|
||||||
|
if (options?.includeWildcard && identifiers.some(id => id.value === `*.${certDomainName}`)) {
|
||||||
|
// If wildcard was successfully added, include it as alt name
|
||||||
|
csrDomains.push(`*.${certDomainName}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const [key, csr] = await plugins.acme.forge.createCsr({
|
const [key, csr] = await plugins.acme.forge.createCsr({
|
||||||
commonName: `*.${certDomainName}`,
|
commonName,
|
||||||
altNames: [certDomainName],
|
altNames: csrDomains,
|
||||||
});
|
});
|
||||||
|
|
||||||
await this.retry(() => this.client.finalizeOrder(order, csr), 'finalizeOrder');
|
await this.retry(() => this.client.finalizeOrder(order, csr), 'finalizeOrder');
|
||||||
|
Loading…
x
Reference in New Issue
Block a user