mirror of
https://github.com/certd/certd.git
synced 2026-04-14 12:30:54 +08:00
fix: 修复aliyun域名超过100个找不到域名的bug
This commit is contained in:
@@ -20,7 +20,8 @@
|
||||
"@certd/acme-client": "workspace:^1.20.10",
|
||||
"@certd/pipeline": "workspace:^1.20.10",
|
||||
"jszip": "^3.10.1",
|
||||
"node-forge": "^0.10.0"
|
||||
"node-forge": "^0.10.0",
|
||||
"psl": "^1.9.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@alicloud/cs20151215": "^3.0.3",
|
||||
@@ -35,6 +36,7 @@
|
||||
"@types/lodash": "^4.14.186",
|
||||
"@types/mocha": "^10.0.0",
|
||||
"@types/node-forge": "^1.3.0",
|
||||
"@types/psl": "^1.1.3",
|
||||
"@typescript-eslint/eslint-plugin": "^5.38.1",
|
||||
"@typescript-eslint/parser": "^5.38.1",
|
||||
"chai": "^4.3.6",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Registrable } from "@certd/pipeline";
|
||||
import { HttpClient, IAccess, ILogger, Registrable } from "@certd/pipeline";
|
||||
|
||||
export type DnsProviderDefine = Registrable & {
|
||||
accessType: string;
|
||||
@@ -11,13 +11,21 @@ export type CreateRecordOptions = {
|
||||
fullRecord: string;
|
||||
type: string;
|
||||
value: any;
|
||||
domain: string;
|
||||
};
|
||||
export type RemoveRecordOptions = CreateRecordOptions & {
|
||||
record: any;
|
||||
};
|
||||
|
||||
export type DnsProviderContext = {
|
||||
access: IAccess;
|
||||
logger: ILogger;
|
||||
http: HttpClient;
|
||||
};
|
||||
|
||||
export interface IDnsProvider {
|
||||
onInstance(): Promise<void>;
|
||||
createRecord(options: CreateRecordOptions): Promise<any>;
|
||||
removeRecord(options: RemoveRecordOptions): Promise<any>;
|
||||
setCtx(ctx: DnsProviderContext): void;
|
||||
}
|
||||
|
||||
15
packages/plugins/plugin-cert/src/dns-provider/base.ts
Normal file
15
packages/plugins/plugin-cert/src/dns-provider/base.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { CreateRecordOptions, DnsProviderContext, IDnsProvider, RemoveRecordOptions } from "./api";
|
||||
|
||||
export abstract class AbstractDnsProvider implements IDnsProvider {
|
||||
ctx!: DnsProviderContext;
|
||||
|
||||
setCtx(ctx: DnsProviderContext) {
|
||||
this.ctx = ctx;
|
||||
}
|
||||
|
||||
abstract createRecord(options: CreateRecordOptions): Promise<any>;
|
||||
|
||||
abstract onInstance(): Promise<void>;
|
||||
|
||||
abstract removeRecord(options: RemoveRecordOptions): Promise<any>;
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
export * from "./api";
|
||||
export * from "./registry";
|
||||
export * from "./decorator";
|
||||
export * from "./base";
|
||||
|
||||
@@ -5,6 +5,8 @@ import { Challenge } from "@certd/acme-client/types/rfc8555";
|
||||
import { Logger } from "log4js";
|
||||
import { IContext } from "@certd/pipeline";
|
||||
import { IDnsProvider } from "../../dns-provider";
|
||||
import psl from "psl";
|
||||
|
||||
export type CertInfo = {
|
||||
crt: string;
|
||||
key: string;
|
||||
@@ -65,33 +67,43 @@ export class AcmeService {
|
||||
return key.toString();
|
||||
}
|
||||
|
||||
parseDomain(fullDomain: string) {
|
||||
const parsed = psl.parse(fullDomain) as psl.ParsedDomain;
|
||||
if (parsed.error) {
|
||||
throw new Error(`解析${fullDomain}域名失败:` + JSON.stringify(parsed.error));
|
||||
}
|
||||
return parsed.domain as string;
|
||||
}
|
||||
async challengeCreateFn(authz: any, challenge: any, keyAuthorization: string, dnsProvider: IDnsProvider) {
|
||||
this.logger.info("Triggered challengeCreateFn()");
|
||||
|
||||
/* http-01 */
|
||||
const fullDomain = authz.identifier.value;
|
||||
if (challenge.type === "http-01") {
|
||||
const filePath = `/var/www/html/.well-known/acme-challenge/${challenge.token}`;
|
||||
const fileContents = keyAuthorization;
|
||||
|
||||
this.logger.info(`Creating challenge response for ${authz.identifier.value} at path: ${filePath}`);
|
||||
this.logger.info(`Creating challenge response for ${fullDomain} at path: ${filePath}`);
|
||||
|
||||
/* Replace this */
|
||||
this.logger.info(`Would write "${fileContents}" to path "${filePath}"`);
|
||||
// await fs.writeFileAsync(filePath, fileContents);
|
||||
} else if (challenge.type === "dns-01") {
|
||||
/* dns-01 */
|
||||
const dnsRecord = `_acme-challenge.${authz.identifier.value}`;
|
||||
const dnsRecord = `_acme-challenge.${fullDomain}`;
|
||||
const recordValue = keyAuthorization;
|
||||
|
||||
this.logger.info(`Creating TXT record for ${authz.identifier.value}: ${dnsRecord}`);
|
||||
|
||||
this.logger.info(`Creating TXT record for ${fullDomain}: ${dnsRecord}`);
|
||||
/* Replace this */
|
||||
this.logger.info(`Would create TXT record "${dnsRecord}" with value "${recordValue}"`);
|
||||
|
||||
const domain = this.parseDomain(fullDomain);
|
||||
this.logger.info("解析到域名domain=", domain);
|
||||
return await dnsProvider.createRecord({
|
||||
fullRecord: dnsRecord,
|
||||
type: "TXT",
|
||||
value: recordValue,
|
||||
domain,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -111,28 +123,33 @@ export class AcmeService {
|
||||
this.logger.info("Triggered challengeRemoveFn()");
|
||||
|
||||
/* http-01 */
|
||||
const fullDomain = authz.identifier.value;
|
||||
if (challenge.type === "http-01") {
|
||||
const filePath = `/var/www/html/.well-known/acme-challenge/${challenge.token}`;
|
||||
|
||||
this.logger.info(`Removing challenge response for ${authz.identifier.value} at path: ${filePath}`);
|
||||
this.logger.info(`Removing challenge response for ${fullDomain} at path: ${filePath}`);
|
||||
|
||||
/* Replace this */
|
||||
this.logger.info(`Would remove file on path "${filePath}"`);
|
||||
// await fs.unlinkAsync(filePath);
|
||||
} else if (challenge.type === "dns-01") {
|
||||
const dnsRecord = `_acme-challenge.${authz.identifier.value}`;
|
||||
const dnsRecord = `_acme-challenge.${fullDomain}`;
|
||||
const recordValue = keyAuthorization;
|
||||
|
||||
this.logger.info(`Removing TXT record for ${authz.identifier.value}: ${dnsRecord}`);
|
||||
this.logger.info(`Removing TXT record for ${fullDomain}: ${dnsRecord}`);
|
||||
|
||||
/* Replace this */
|
||||
this.logger.info(`Would remove TXT record "${dnsRecord}" with value "${recordValue}"`);
|
||||
|
||||
const domain = this.parseDomain(fullDomain);
|
||||
|
||||
try {
|
||||
await dnsProvider.removeRecord({
|
||||
fullRecord: dnsRecord,
|
||||
type: "TXT",
|
||||
value: keyAuthorization,
|
||||
record: recordItem,
|
||||
domain,
|
||||
});
|
||||
} catch (e) {
|
||||
this.logger.error("删除解析记录出错:", e);
|
||||
|
||||
@@ -1,21 +1,10 @@
|
||||
import {
|
||||
AbstractTaskPlugin,
|
||||
Decorator,
|
||||
HttpClient,
|
||||
IAccessService,
|
||||
IContext,
|
||||
IsTaskPlugin,
|
||||
RunStrategy,
|
||||
Step,
|
||||
TaskInput,
|
||||
TaskOutput
|
||||
} from "@certd/pipeline";
|
||||
import { AbstractTaskPlugin, Decorator, HttpClient, IAccessService, IContext, IsTaskPlugin, RunStrategy, Step, TaskInput, TaskOutput } from "@certd/pipeline";
|
||||
import dayjs from "dayjs";
|
||||
import {AcmeService, CertInfo} from "./acme";
|
||||
import { AcmeService, CertInfo } from "./acme";
|
||||
import _ from "lodash";
|
||||
import {Logger} from "log4js";
|
||||
import {DnsProviderDefine, dnsProviderRegistry} from "../../dns-provider";
|
||||
import {CertReader} from "./cert-reader";
|
||||
import { Logger } from "log4js";
|
||||
import { DnsProviderContext, DnsProviderDefine, dnsProviderRegistry } from "../../dns-provider";
|
||||
import { CertReader } from "./cert-reader";
|
||||
import JSZip from "jszip";
|
||||
|
||||
export { CertReader };
|
||||
@@ -242,8 +231,9 @@ export class CertApplyPlugin extends AbstractTaskPlugin {
|
||||
|
||||
// @ts-ignore
|
||||
const dnsProvider: IDnsProvider = new DnsProviderClass();
|
||||
const context = { access, logger: this.logger, http: this.http };
|
||||
const context: DnsProviderContext = { access, logger: this.logger, http: this.http };
|
||||
Decorator.inject(dnsProviderDefine.autowire, dnsProvider, context);
|
||||
dnsProvider.setCtx(context);
|
||||
await dnsProvider.onInstance();
|
||||
|
||||
const cert = await this.acme.order({
|
||||
|
||||
Reference in New Issue
Block a user