mirror of https://github.com/certd/certd
				
				
				
			perf: 优化证书申请成功率
							parent
							
								
									453f1baa0b
								
							
						
					
					
						commit
						968c4690a0
					
				| 
						 | 
				
			
			@ -137,7 +137,12 @@ module.exports = async (client, userOpts) => {
 | 
			
		|||
                }
 | 
			
		||||
                else {
 | 
			
		||||
                    log(`[auto] [${d}] Running challenge verification`);
 | 
			
		||||
                    await client.verifyChallenge(authz, challenge);
 | 
			
		||||
                    try {
 | 
			
		||||
                        await client.verifyChallenge(authz, challenge);
 | 
			
		||||
                    }
 | 
			
		||||
                    catch (e) {
 | 
			
		||||
                        log(`[auto] [${d}] challenge verification threw error: ${e.message}`);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                /* Complete challenge and wait for valid status */
 | 
			
		||||
| 
						 | 
				
			
			@ -170,11 +175,41 @@ module.exports = async (client, userOpts) => {
 | 
			
		|||
            throw e;
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
    const domainSets = [];
 | 
			
		||||
 | 
			
		||||
    const challengePromises = authorizations.map((authz) => async () => {
 | 
			
		||||
        await challengeFunc(authz);
 | 
			
		||||
    authorizations.forEach((authz) => {
 | 
			
		||||
        const d = authz.identifier.value;
 | 
			
		||||
        let setd = false;
 | 
			
		||||
        // eslint-disable-next-line no-restricted-syntax
 | 
			
		||||
        for (const group of domainSets) {
 | 
			
		||||
            if (!group[d]) {
 | 
			
		||||
                group[d] = authz;
 | 
			
		||||
                setd = true;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (!setd) {
 | 
			
		||||
            const group = {};
 | 
			
		||||
            group[d] = authz;
 | 
			
		||||
            domainSets.push(group);
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    const allChallengePromises = [];
 | 
			
		||||
    // eslint-disable-next-line no-restricted-syntax
 | 
			
		||||
    for (const domainSet of domainSets) {
 | 
			
		||||
        const challengePromises = [];
 | 
			
		||||
        // eslint-disable-next-line guard-for-in,no-restricted-syntax
 | 
			
		||||
        for (const domain in domainSet) {
 | 
			
		||||
            const authz = domainSet[domain];
 | 
			
		||||
            challengePromises.push(async () => {
 | 
			
		||||
                log(`[auto] [${domain}] Starting challenge`);
 | 
			
		||||
                await challengeFunc(authz);
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
        allChallengePromises.push(challengePromises);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    log(`[auto] challengeGroups:${allChallengePromises.length}`);
 | 
			
		||||
    function runAllPromise(tasks) {
 | 
			
		||||
        let promise = Promise.resolve();
 | 
			
		||||
        tasks.forEach((task) => {
 | 
			
		||||
| 
						 | 
				
			
			@ -195,9 +230,15 @@ module.exports = async (client, userOpts) => {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
        log('开始challenge');
 | 
			
		||||
        await runPromisePa(challengePromises);
 | 
			
		||||
 | 
			
		||||
        log(`开始challenge,共${allChallengePromises.length}组`);
 | 
			
		||||
        let i = 0;
 | 
			
		||||
        // eslint-disable-next-line no-restricted-syntax
 | 
			
		||||
        for (const challengePromises of allChallengePromises) {
 | 
			
		||||
            i += 1;
 | 
			
		||||
            log(`开始第${i}组`);
 | 
			
		||||
            // eslint-disable-next-line no-await-in-loop
 | 
			
		||||
            await runPromisePa(challengePromises);
 | 
			
		||||
        }
 | 
			
		||||
        log('challenge结束');
 | 
			
		||||
 | 
			
		||||
        // log('[auto] Waiting for challenge valid status');
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -55,7 +55,7 @@ class HttpClient {
 | 
			
		|||
     */
 | 
			
		||||
 | 
			
		||||
    async request(url, method, opts = {}) {
 | 
			
		||||
        if (this.urlMapping && this.urlMapping.enabled === true && this.urlMapping.mappings) {
 | 
			
		||||
        if (this.urlMapping && this.urlMapping.mappings) {
 | 
			
		||||
            // eslint-disable-next-line no-restricted-syntax
 | 
			
		||||
            for (const key in this.urlMapping.mappings) {
 | 
			
		||||
                if (url.includes(key)) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -72,7 +72,7 @@ async function spawn(opts: SpawnOption): Promise<string> {
 | 
			
		|||
  let stderr = "";
 | 
			
		||||
  return safePromise((resolve, reject) => {
 | 
			
		||||
    const ls = childProcess.spawn(cmd, {
 | 
			
		||||
      shell: process.platform == "win32",
 | 
			
		||||
      shell: true,
 | 
			
		||||
      env: {
 | 
			
		||||
        ...process.env,
 | 
			
		||||
        ...opts.env,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,7 +13,7 @@ export type CertInfo = {
 | 
			
		|||
  key: string;
 | 
			
		||||
  csr: string;
 | 
			
		||||
};
 | 
			
		||||
export type SSLProvider = "letsencrypt" | "buypass" | "zerossl";
 | 
			
		||||
export type SSLProvider = "letsencrypt" | "google" | "zerossl";
 | 
			
		||||
type AcmeServiceOptions = {
 | 
			
		||||
  userContext: IContext;
 | 
			
		||||
  logger: Logger;
 | 
			
		||||
| 
						 | 
				
			
			@ -42,10 +42,18 @@ export class AcmeService {
 | 
			
		|||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async getAccountConfig(email: string): Promise<any> {
 | 
			
		||||
  async getAccountConfig(email: string, urlMapping: UrlMapping): Promise<any> {
 | 
			
		||||
    const conf = (await this.userContext.getObj(this.buildAccountKey(email))) || {};
 | 
			
		||||
    if (conf.accountUrl?.indexOf("letsencrypt.proxy.handsfree.work")) {
 | 
			
		||||
      conf.accountUrl = conf.accountUrl.replace("letsencrypt.proxy.handsfree.work", "acme-v02.api.letsencrypt.org");
 | 
			
		||||
    if (urlMapping && urlMapping.mappings) {
 | 
			
		||||
      for (const key in urlMapping.mappings) {
 | 
			
		||||
        if (Object.prototype.hasOwnProperty.call(urlMapping.mappings, key)) {
 | 
			
		||||
          const element = urlMapping.mappings[key];
 | 
			
		||||
          if (conf.accountUrl?.indexOf(element) > -1) {
 | 
			
		||||
            //如果用了代理url,要替换回去
 | 
			
		||||
            conf.accountUrl = conf.accountUrl.replace(element, key);
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return conf;
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			@ -59,7 +67,14 @@ export class AcmeService {
 | 
			
		|||
  }
 | 
			
		||||
 | 
			
		||||
  async getAcmeClient(email: string, isTest = false): Promise<acme.Client> {
 | 
			
		||||
    const conf = await this.getAccountConfig(email);
 | 
			
		||||
    const urlMapping: UrlMapping = {
 | 
			
		||||
      enabled: false,
 | 
			
		||||
      mappings: {
 | 
			
		||||
        "acme-v02.api.letsencrypt.org": "letsencrypt.proxy.handsfree.work",
 | 
			
		||||
        "dv.acme-v02.api.pki.goog": "google.proxy.handsfree.work",
 | 
			
		||||
      },
 | 
			
		||||
    };
 | 
			
		||||
    const conf = await this.getAccountConfig(email, urlMapping);
 | 
			
		||||
    if (conf.key == null) {
 | 
			
		||||
      conf.key = await this.createNewKey();
 | 
			
		||||
      await this.saveAccountConfig(email, conf);
 | 
			
		||||
| 
						 | 
				
			
			@ -70,19 +85,15 @@ export class AcmeService {
 | 
			
		|||
    } else {
 | 
			
		||||
      directoryUrl = acme.directory[this.sslProvider].production;
 | 
			
		||||
    }
 | 
			
		||||
    const urlMapping: UrlMapping = { enabled: false, mappings: {} };
 | 
			
		||||
    if (this.options.useMappingProxy) {
 | 
			
		||||
      urlMapping.enabled = true;
 | 
			
		||||
      urlMapping.mappings = {
 | 
			
		||||
        "acme-v02.api.letsencrypt.org": "letsencrypt.proxy.handsfree.work",
 | 
			
		||||
      };
 | 
			
		||||
    }
 | 
			
		||||
    const client = new acme.Client({
 | 
			
		||||
      directoryUrl: directoryUrl,
 | 
			
		||||
      accountKey: conf.key,
 | 
			
		||||
      accountUrl: conf.accountUrl,
 | 
			
		||||
      externalAccountBinding: this.eab,
 | 
			
		||||
      backoffAttempts: 30,
 | 
			
		||||
      backoffAttempts: 15,
 | 
			
		||||
      backoffMin: 5000,
 | 
			
		||||
      backoffMax: 10000,
 | 
			
		||||
      urlMapping,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -34,7 +34,7 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
 | 
			
		|||
      options: [
 | 
			
		||||
        { value: "letsencrypt", label: "Let's Encrypt" },
 | 
			
		||||
        // { value: "letsencrypt-proxy", label: "Let's Encrypt代理,letsencrypt.org无法访问时使用" },
 | 
			
		||||
        // { value: "buypass", label: "Buypass" },
 | 
			
		||||
        { value: "google", label: "Google" },
 | 
			
		||||
        { value: "zerossl", label: "ZeroSSL" },
 | 
			
		||||
      ],
 | 
			
		||||
    },
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -55,7 +55,7 @@
 | 
			
		|||
            <a-input v-model:value="testFormState.receiver" />
 | 
			
		||||
          </a-form-item>
 | 
			
		||||
          <a-form-item :wrapper-col="{ offset: 8, span: 16 }">
 | 
			
		||||
            <a-button type="primary" html-type="submit">测试</a-button>
 | 
			
		||||
            <a-button type="primary" :loading="testFormState.loading" html-type="submit">测试</a-button>
 | 
			
		||||
          </a-form-item>
 | 
			
		||||
        </a-form>
 | 
			
		||||
      </div>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,3 +6,6 @@ typeorm:
 | 
			
		|||
    default:
 | 
			
		||||
      logging: false
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
plus:
 | 
			
		||||
  serverBaseUrl: 'https://api.ai.handsfree.work/'
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -88,6 +88,9 @@ const development = {
 | 
			
		|||
  system: {
 | 
			
		||||
    resetAdminPasswd: false,
 | 
			
		||||
  },
 | 
			
		||||
  plus: {
 | 
			
		||||
    serverBaseUrl: 'http://127.0.0.1:11007',
 | 
			
		||||
  },
 | 
			
		||||
} as MidwayConfig;
 | 
			
		||||
mergeConfig(development, 'development');
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue