mirror of https://github.com/certd/certd
				
				
				
			perf: 优化acme sdk
							parent
							
								
									03b751fa13
								
							
						
					
					
						commit
						54db744282
					
				|  | @ -99,31 +99,14 @@ export default  async (client, userOpts) => { | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         try { |         const keyAuthorizationGetter = async (challenge) => { | ||||||
|             /* Select challenge based on priority */ |             return await client.getChallengeKeyAuthorization(challenge); | ||||||
|             const challenge = authz.challenges.sort((a, b) => { |  | ||||||
|                 const aidx = opts.challengePriority.indexOf(a.type); |  | ||||||
|                 const bidx = opts.challengePriority.indexOf(b.type); |  | ||||||
| 
 |  | ||||||
|                 if (aidx === -1) return 1; |  | ||||||
|                 if (bidx === -1) return -1; |  | ||||||
|                 return aidx - bidx; |  | ||||||
|             }).slice(0, 1)[0]; |  | ||||||
| 
 |  | ||||||
|             if (!challenge) { |  | ||||||
|                 throw new Error(`Unable to select challenge for ${d}, no challenge found`); |  | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|             log(`[auto] [${d}] Found ${authz.challenges.length} challenges, selected type: ${challenge.type}`); |  | ||||||
| 
 |  | ||||||
|             /* Trigger challengeCreateFn() */ |  | ||||||
|             log(`[auto] [${d}] Trigger challengeCreateFn()`); |  | ||||||
|             const keyAuthorization = await client.getChallengeKeyAuthorization(challenge); |  | ||||||
| 
 |  | ||||||
|         try { |         try { | ||||||
|                 const { recordReq, recordRes, dnsProvider } = await opts.challengeCreateFn(authz, challenge, keyAuthorization); |             log(`[auto] [${d}] Trigger challengeCreateFn()`); | ||||||
|                 log(`[auto] [${d}] challengeCreateFn success`); |             try { | ||||||
|                 log(`[auto] [${d}] add challengeRemoveFn()`); |                 const { recordReq, recordRes, dnsProvider,challenge ,keyAuthorization} = await opts.challengeCreateFn(authz, keyAuthorizationGetter); | ||||||
|                 clearTasks.push(async () => { |                 clearTasks.push(async () => { | ||||||
|                     /* Trigger challengeRemoveFn(), suppress errors */ |                     /* Trigger challengeRemoveFn(), suppress errors */ | ||||||
|                     log(`[auto] [${d}] Trigger challengeRemoveFn()`); |                     log(`[auto] [${d}] Trigger challengeRemoveFn()`); | ||||||
|  | @ -141,7 +124,7 @@ export default  async (client, userOpts) => { | ||||||
|                     await wait(60 * 1000); |                     await wait(60 * 1000); | ||||||
|                 } |                 } | ||||||
|                 else { |                 else { | ||||||
|                     log(`[auto] [${d}] Running challenge verification`); |                     log(`[auto] [${d}] Running challenge verification, type = ${challenge.type}`); | ||||||
|                     try { |                     try { | ||||||
|                         await client.verifyChallenge(authz, challenge); |                         await client.verifyChallenge(authz, challenge); | ||||||
|                     } |                     } | ||||||
|  |  | ||||||
|  | @ -5,3 +5,5 @@ export class CancelError extends Error { | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |  | ||||||
|  | @ -4,6 +4,8 @@ | ||||||
| 
 | 
 | ||||||
| import { AxiosInstance } from 'axios'; | import { AxiosInstance } from 'axios'; | ||||||
| import * as rfc8555 from './rfc8555'; | import * as rfc8555 from './rfc8555'; | ||||||
|  | import {CancelError} from '../src/error.js' | ||||||
|  | export * from '../src/error.js' | ||||||
| 
 | 
 | ||||||
| export type PrivateKeyBuffer = Buffer; | export type PrivateKeyBuffer = Buffer; | ||||||
| export type PublicKeyBuffer = Buffer; | export type PublicKeyBuffer = Buffer; | ||||||
|  | @ -56,7 +58,7 @@ export interface ClientExternalAccountBindingOptions { | ||||||
| 
 | 
 | ||||||
| export interface ClientAutoOptions { | export interface ClientAutoOptions { | ||||||
|     csr: CsrBuffer | CsrString; |     csr: CsrBuffer | CsrString; | ||||||
|     challengeCreateFn: (authz: Authorization, challenge: rfc8555.Challenge, keyAuthorization: string) => Promise<{recordReq:any,recordRes:any,dnsProvider:any}>; |     challengeCreateFn: (authz: Authorization, keyAuthorization: (challenge:rfc8555.Challenge)=>Promise<string>) => Promise<{recordReq?:any,recordRes?:any,dnsProvider?:any,challenge: rfc8555.Challenge,keyAuthorization:string}>; | ||||||
|     challengeRemoveFn: (authz: Authorization, challenge: rfc8555.Challenge, keyAuthorization: string,recordReq:any, recordRes:any,dnsProvider:any) => Promise<any>; |     challengeRemoveFn: (authz: Authorization, challenge: rfc8555.Challenge, keyAuthorization: string,recordReq:any, recordRes:any,dnsProvider:any) => Promise<any>; | ||||||
|     email?: string; |     email?: string; | ||||||
|     termsOfServiceAgreed?: boolean; |     termsOfServiceAgreed?: boolean; | ||||||
|  | @ -202,4 +204,4 @@ export function setLogger(fn: (message: any, ...args: any[]) => void): void; | ||||||
| 
 | 
 | ||||||
| export function walkTxtRecord(record: any): Promise<string[]>; | export function walkTxtRecord(record: any): Promise<string[]>; | ||||||
| 
 | 
 | ||||||
| export const CancelError: Error; | export const CancelError: typeof CancelError; | ||||||
|  | @ -7,7 +7,6 @@ import { IContext } from "@certd/pipeline"; | ||||||
| import { ILogger, utils } from "@certd/basic"; | import { ILogger, utils } from "@certd/basic"; | ||||||
| import { IDnsProvider, parseDomain } from "../../dns-provider/index.js"; | import { IDnsProvider, parseDomain } from "../../dns-provider/index.js"; | ||||||
| import { HttpChallengeUploader } from "./uploads/api.js"; | import { HttpChallengeUploader } from "./uploads/api.js"; | ||||||
| 
 |  | ||||||
| export type CnameVerifyPlan = { | export type CnameVerifyPlan = { | ||||||
|   type?: string; |   type?: string; | ||||||
|   domain: string; |   domain: string; | ||||||
|  | @ -170,75 +169,36 @@ export class AcmeService { | ||||||
|     return key.toString(); |     return key.toString(); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async challengeCreateFn(authz: any, challenge: any, keyAuthorization: string, providers: Providers) { |   async challengeCreateFn(authz: any, keyAuthorizationGetter: (challenge: Challenge) => Promise<string>, providers: Providers) { | ||||||
|     this.logger.info("Triggered challengeCreateFn()"); |     this.logger.info("Triggered challengeCreateFn()"); | ||||||
| 
 | 
 | ||||||
|     /* http-01 */ |  | ||||||
|     const fullDomain = authz.identifier.value; |     const fullDomain = authz.identifier.value; | ||||||
|     if (challenge.type === "http-01") { |     let domain = parseDomain(fullDomain); | ||||||
|  |     this.logger.info("主域名为:" + domain); | ||||||
|  | 
 | ||||||
|  |     const getChallenge = (type: string) => { | ||||||
|  |       return authz.challenges.find((c: any) => c.type === type); | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     const doHttpVerify = async (challenge: any, httpUploader: HttpChallengeUploader) => { | ||||||
|  |       const keyAuthorization = await keyAuthorizationGetter(challenge); | ||||||
|  |       this.logger.info("http校验"); | ||||||
|       const filePath = `.well-known/acme-challenge/${challenge.token}`; |       const filePath = `.well-known/acme-challenge/${challenge.token}`; | ||||||
|       const fileContents = keyAuthorization; |       const fileContents = keyAuthorization; | ||||||
|       this.logger.info(`校验 ${fullDomain} ,准备上传文件:${filePath}`); |       this.logger.info(`校验 ${fullDomain} ,准备上传文件:${filePath}`); | ||||||
| 
 |       await httpUploader.upload(filePath, fileContents); | ||||||
|       let httpUploaderPlan: HttpVerifyPlan = null; |  | ||||||
|       if (providers.domainsVerifyPlan) { |  | ||||||
|         //查找文件上传配置
 |  | ||||||
|         for (const mainDomain in providers.domainsVerifyPlan) { |  | ||||||
|           const domainVerifyPlan = providers.domainsVerifyPlan[mainDomain]; |  | ||||||
|           if (domainVerifyPlan && domainVerifyPlan.type === "http" && domainVerifyPlan.httpVerifyPlan[fullDomain]) { |  | ||||||
|             httpUploaderPlan = domainVerifyPlan.httpVerifyPlan[fullDomain]; |  | ||||||
|             break; |  | ||||||
|           } |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|       if (httpUploaderPlan == null) { |  | ||||||
|         throw new Error(`未找到域名【${fullDomain}】的http校验计划`); |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|       await httpUploaderPlan.httpUploader.upload(filePath, fileContents); |  | ||||||
|       this.logger.info(`上传文件【${filePath}】成功`); |       this.logger.info(`上传文件【${filePath}】成功`); | ||||||
|     } else if (challenge.type === "dns-01") { |       return { | ||||||
|       /* dns-01 */ |         challenge, | ||||||
|       let fullRecord = `_acme-challenge.${fullDomain}`; |         keyAuthorization, | ||||||
|  |       }; | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     const doDnsVerify = async (challenge: any, fullRecord: string, dnsProvider: IDnsProvider) => { | ||||||
|  |       this.logger.info("dns校验"); | ||||||
|  |       const keyAuthorization = await keyAuthorizationGetter(challenge); | ||||||
|  | 
 | ||||||
|       const recordValue = keyAuthorization; |       const recordValue = keyAuthorization; | ||||||
| 
 |  | ||||||
|       this.logger.info(`Creating TXT record for ${fullDomain}: ${fullRecord}`); |  | ||||||
|       /* Replace this */ |  | ||||||
|       this.logger.info(`Would create TXT record "${fullRecord}" with value "${recordValue}"`); |  | ||||||
| 
 |  | ||||||
|       let domain = parseDomain(fullDomain); |  | ||||||
|       this.logger.info("解析到域名domain=" + domain); |  | ||||||
| 
 |  | ||||||
|       let dnsProvider = providers.dnsProvider; |  | ||||||
|       if (providers.domainsVerifyPlan) { |  | ||||||
|         //按照计划执行
 |  | ||||||
|         const domainVerifyPlan = providers.domainsVerifyPlan[domain]; |  | ||||||
|         if (domainVerifyPlan) { |  | ||||||
|           if (domainVerifyPlan.type === "dns") { |  | ||||||
|             dnsProvider = domainVerifyPlan.dnsProvider; |  | ||||||
|           } else if (domainVerifyPlan.type === "cname") { |  | ||||||
|             const cnameVerifyPlan = domainVerifyPlan.cnameVerifyPlan; |  | ||||||
|             if (cnameVerifyPlan) { |  | ||||||
|               const cname = cnameVerifyPlan[fullDomain]; |  | ||||||
|               if (cname) { |  | ||||||
|                 dnsProvider = cname.dnsProvider; |  | ||||||
|                 domain = parseDomain(cname.domain); |  | ||||||
|                 fullRecord = cname.fullRecord; |  | ||||||
|               } |  | ||||||
|             } else { |  | ||||||
|               this.logger.error("未找到域名Cname校验计划,使用默认的dnsProvider"); |  | ||||||
|             } |  | ||||||
|           } else if (domainVerifyPlan.type === "http") { |  | ||||||
|             throw new Error("切换为http校验"); |  | ||||||
|           } else { |  | ||||||
|             // this.logger.error("不支持的校验类型", domainVerifyPlan.type);
 |  | ||||||
|             throw new Error("不支持的校验类型", domainVerifyPlan.type); |  | ||||||
|           } |  | ||||||
|         } else { |  | ||||||
|           this.logger.info("未找到域名校验计划,使用默认的dnsProvider"); |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|       let hostRecord = fullRecord.replace(`${domain}`, ""); |       let hostRecord = fullRecord.replace(`${domain}`, ""); | ||||||
|       if (hostRecord.endsWith(".")) { |       if (hostRecord.endsWith(".")) { | ||||||
|         hostRecord = hostRecord.substring(0, hostRecord.length - 1); |         hostRecord = hostRecord.substring(0, hostRecord.length - 1); | ||||||
|  | @ -258,8 +218,50 @@ export class AcmeService { | ||||||
|         recordReq, |         recordReq, | ||||||
|         recordRes, |         recordRes, | ||||||
|         dnsProvider, |         dnsProvider, | ||||||
|  |         challenge, | ||||||
|  |         keyAuthorization, | ||||||
|       }; |       }; | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     let dnsProvider = providers.dnsProvider; | ||||||
|  |     let fullRecord = `_acme-challenge.${fullDomain}`; | ||||||
|  | 
 | ||||||
|  |     if (providers.domainsVerifyPlan) { | ||||||
|  |       //按照计划执行
 | ||||||
|  |       const domainVerifyPlan = providers.domainsVerifyPlan[domain]; | ||||||
|  |       if (domainVerifyPlan) { | ||||||
|  |         if (domainVerifyPlan.type === "dns") { | ||||||
|  |           dnsProvider = domainVerifyPlan.dnsProvider; | ||||||
|  |         } else if (domainVerifyPlan.type === "cname") { | ||||||
|  |           const cnameVerifyPlan = domainVerifyPlan.cnameVerifyPlan; | ||||||
|  |           if (cnameVerifyPlan) { | ||||||
|  |             const cname = cnameVerifyPlan[fullDomain]; | ||||||
|  |             if (cname) { | ||||||
|  |               dnsProvider = cname.dnsProvider; | ||||||
|  |               domain = parseDomain(cname.domain); | ||||||
|  |               fullRecord = cname.fullRecord; | ||||||
|             } |             } | ||||||
|  |           } else { | ||||||
|  |             this.logger.error("未找到域名Cname校验计划,使用默认的dnsProvider"); | ||||||
|  |           } | ||||||
|  |         } else if (domainVerifyPlan.type === "http") { | ||||||
|  |           const httpVerifyPlan = domainVerifyPlan.httpVerifyPlan; | ||||||
|  |           if (httpVerifyPlan) { | ||||||
|  |             const httpChallenge = getChallenge("http-01"); | ||||||
|  |             return await doHttpVerify(httpChallenge, httpVerifyPlan[fullDomain].httpUploader); | ||||||
|  |           } else { | ||||||
|  |             throw new Error("未找到域名【" + fullDomain + "】的http校验配置"); | ||||||
|  |           } | ||||||
|  |         } else { | ||||||
|  |           throw new Error("不支持的校验类型", domainVerifyPlan.type); | ||||||
|  |         } | ||||||
|  |       } else { | ||||||
|  |         this.logger.info("未找到域名校验计划,使用默认的dnsProvider"); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     const dnsChallenge = getChallenge("dns-01"); | ||||||
|  |     return await doDnsVerify(dnsChallenge, fullRecord, dnsProvider); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   /** |   /** | ||||||
|  | @ -376,10 +378,9 @@ export class AcmeService { | ||||||
|       challengePriority: ["dns-01", "http-01"], |       challengePriority: ["dns-01", "http-01"], | ||||||
|       challengeCreateFn: async ( |       challengeCreateFn: async ( | ||||||
|         authz: acme.Authorization, |         authz: acme.Authorization, | ||||||
|         challenge: Challenge, |         keyAuthorizationGetter: (challenge: Challenge) => Promise<string> | ||||||
|         keyAuthorization: string |       ): Promise<{ recordReq?: any; recordRes?: any; dnsProvider?: any; challenge: Challenge; keyAuthorization: string }> => { | ||||||
|       ): Promise<{ recordReq: any; recordRes: any; dnsProvider: any }> => { |         return await this.challengeCreateFn(authz, keyAuthorizationGetter, providers); | ||||||
|         return await this.challengeCreateFn(authz, challenge, keyAuthorization, providers); |  | ||||||
|       }, |       }, | ||||||
|       challengeRemoveFn: async ( |       challengeRemoveFn: async ( | ||||||
|         authz: acme.Authorization, |         authz: acme.Authorization, | ||||||
|  |  | ||||||
|  | @ -19,6 +19,7 @@ | ||||||
|     "@certd/basic": "^1.29.2", |     "@certd/basic": "^1.29.2", | ||||||
|     "@certd/pipeline": "^1.29.2", |     "@certd/pipeline": "^1.29.2", | ||||||
|     "@kubernetes/client-node": "0.21.0", |     "@kubernetes/client-node": "0.21.0", | ||||||
|  |     "ali-oss": "^6.21.0", | ||||||
|     "basic-ftp": "^5.0.5", |     "basic-ftp": "^5.0.5", | ||||||
|     "dayjs": "^1.11.7", |     "dayjs": "^1.11.7", | ||||||
|     "iconv-lite": "^0.6.3", |     "iconv-lite": "^0.6.3", | ||||||
|  |  | ||||||
|  | @ -13,9 +13,12 @@ export class AliossClient { | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async init() { |   async init() { | ||||||
|  |     if (this.client) { | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|     // @ts-ignore
 |     // @ts-ignore
 | ||||||
|     const OSS = await import("ali-oss"); |     const OSS = await import("ali-oss"); | ||||||
|     this.client = new OSS.default({ |     const ossClient = new OSS.default({ | ||||||
|       accessKeyId: this.access.accessKeyId, |       accessKeyId: this.access.accessKeyId, | ||||||
|       accessKeySecret: this.access.accessKeySecret, |       accessKeySecret: this.access.accessKeySecret, | ||||||
|       // yourRegion填写Bucket所在地域。以华东1(杭州)为例,Region填写为oss-cn-hangzhou。
 |       // yourRegion填写Bucket所在地域。以华东1(杭州)为例,Region填写为oss-cn-hangzhou。
 | ||||||
|  | @ -25,16 +28,20 @@ export class AliossClient { | ||||||
|       // yourBucketName填写Bucket名称。
 |       // yourBucketName填写Bucket名称。
 | ||||||
|       bucket: this.bucket, |       bucket: this.bucket, | ||||||
|     }); |     }); | ||||||
|  |     // oss
 | ||||||
|  | 
 | ||||||
|  |     this.client = ossClient; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async doRequest(client: any, bucket: string, xml: string, params: any) { |   async doRequest(bucket: string, xml: string, params: any) { | ||||||
|     params = client._bucketRequestParams("POST", bucket, { |     await this.init(); | ||||||
|  |     params = this.client._bucketRequestParams("POST", bucket, { | ||||||
|       ...params, |       ...params, | ||||||
|     }); |     }); | ||||||
|     params.content = xml; |     params.content = xml; | ||||||
|     params.mime = "xml"; |     params.mime = "xml"; | ||||||
|     params.successStatuses = [200]; |     params.successStatuses = [200]; | ||||||
|     const res = await client.request(params); |     const res = await this.client.request(params); | ||||||
|     this.checkRet(res); |     this.checkRet(res); | ||||||
|     return res; |     return res; | ||||||
|   } |   } | ||||||
|  | @ -46,11 +53,12 @@ export class AliossClient { | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async uploadFile(filePath: string, content: Buffer) { |   async uploadFile(filePath: string, content: Buffer) { | ||||||
|     const memFile = new File([content], filePath); |     await this.init(); | ||||||
|     return await this.client.put(filePath, memFile); |     return await this.client.put(filePath, content); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async removeFile(filePath: string) { |   async removeFile(filePath: string) { | ||||||
|  |     await this.init(); | ||||||
|     return await this.client.delete(filePath); |     return await this.client.delete(filePath); | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	 xiaojunnuo
						xiaojunnuo