perf: 优化证书申请成功率

pull/148/head
xiaojunnuo 2024-08-23 13:15:06 +08:00
parent 453f1baa0b
commit 968c4690a0
8 changed files with 78 additions and 20 deletions

View File

@ -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');

View File

@ -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)) {

View File

@ -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,

View File

@ -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,

View File

@ -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" },
],
},

View File

@ -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>

View File

@ -6,3 +6,6 @@ typeorm:
default:
logging: false
plus:
serverBaseUrl: 'https://api.ai.handsfree.work/'

View File

@ -88,6 +88,9 @@ const development = {
system: {
resetAdminPasswd: false,
},
plus: {
serverBaseUrl: 'http://127.0.0.1:11007',
},
} as MidwayConfig;
mergeConfig(development, 'development');