diff --git a/packages/core/basic/src/utils/util.env.ts b/packages/core/basic/src/utils/util.env.ts index 1427b882..65983bca 100644 --- a/packages/core/basic/src/utils/util.env.ts +++ b/packages/core/basic/src/utils/util.env.ts @@ -1,3 +1,4 @@ export function isDev() { - return process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'local'; + const nodeEnv = process.env.NODE_ENV || ''; + return nodeEnv === 'development' || nodeEnv.indexOf('local') >= 0; } diff --git a/packages/core/pipeline/src/service/cname.ts b/packages/core/pipeline/src/service/cname.ts index 5f1fbee3..3fa63e75 100644 --- a/packages/core/pipeline/src/service/cname.ts +++ b/packages/core/pipeline/src/service/cname.ts @@ -3,9 +3,10 @@ import { IAccess } from "../access"; export type CnameProvider = { id: any; domain: string; - dnsProviderType: string; + title?: string; + dnsProviderType?: string; access?: IAccess; - accessId: any; + accessId?: any; }; export type CnameRecord = { @@ -15,6 +16,7 @@ export type CnameRecord = { recordValue: string; cnameProvider: CnameProvider; status: string; + commonDnsProvider?: any; }; export type ICnameProxyService = { getByDomain: (domain: string) => Promise; diff --git a/packages/libs/lib-server/src/system/basic/service/plus-service.ts b/packages/libs/lib-server/src/system/basic/service/plus-service.ts index 0a3037fc..37b29b04 100644 --- a/packages/libs/lib-server/src/system/basic/service/plus-service.ts +++ b/packages/libs/lib-server/src/system/basic/service/plus-service.ts @@ -1,6 +1,6 @@ import { Inject, Provide, Scope, ScopeEnum } from '@midwayjs/core'; import { AppKey, PlusRequestService } from '@certd/plus-core'; -import { http, HttpRequestConfig, logger } from '@certd/basic'; +import { cache, http, HttpRequestConfig, logger } from '@certd/basic'; import { SysInstallInfo, SysLicenseInfo, SysSettingsService } from '../../settings/index.js'; import { merge } from 'lodash-es'; @@ -75,7 +75,7 @@ export class PlusService { data: { userId, appKey: AppKey, - subjectId: this.getSubjectId(), + subjectId: plusRequestService.getSubjectId(), }, }); } @@ -93,9 +93,19 @@ export class PlusService { } async getAccessToken() { + const cacheKey = 'certd:subject:access_token'; + const token = cache.get(cacheKey); + if (token) { + return token; + } const plusRequestService = await this.getPlusRequestService(); await this.register(); - return await plusRequestService.getAccessToken(); + const res = await plusRequestService.getAccessToken(); + const ttl = res.expiresIn * 1000 - Date.now().valueOf(); + cache.set(cacheKey, res.accessToken, { + ttl, + }); + return res.accessToken; } async requestWithToken(config: HttpRequestConfig) { @@ -103,10 +113,15 @@ export class PlusService { const token = await this.getAccessToken(); merge(config, { baseURL: plusRequestService.getBaseURL(), + method: 'post', headers: { - Authorization: token, + Authorization: `Berear ${token}`, }, }); - return await http.request(config); + const res = await http.request(config); + if (res.code !== 0) { + throw new Error(res.message); + } + return res.data; } } diff --git a/packages/plugins/plugin-cert/src/plugin/cert-plugin/index.ts b/packages/plugins/plugin-cert/src/plugin/cert-plugin/index.ts index d9dd28bc..00201263 100644 --- a/packages/plugins/plugin-cert/src/plugin/cert-plugin/index.ts +++ b/packages/plugins/plugin-cert/src/plugin/cert-plugin/index.ts @@ -378,10 +378,14 @@ export class CertApplyPlugin extends CertApplyBasePlugin { } else { for (const key in domainVerifyPlan.cnameVerifyPlan) { const cnameRecord = await this.ctx.cnameProxyService.getByDomain(key); + let dnsProvider = cnameRecord.commonDnsProvider; + if (cnameRecord.cnameProvider.id > 0) { + dnsProvider = await this.createDnsProvider(cnameRecord.cnameProvider.dnsProviderType, cnameRecord.cnameProvider.access); + } cnameVerifyPlan[key] = { domain: cnameRecord.cnameProvider.domain, fullRecord: cnameRecord.recordValue, - dnsProvider: await this.createDnsProvider(cnameRecord.cnameProvider.dnsProviderType, cnameRecord.cnameProvider.access), + dnsProvider, }; } } diff --git a/packages/ui/certd-client/src/components/plugins/cert/domains-verify-plan-editor/cname-record-info.vue b/packages/ui/certd-client/src/components/plugins/cert/domains-verify-plan-editor/cname-record-info.vue index 10fbe4aa..610cbf2d 100644 --- a/packages/ui/certd-client/src/components/plugins/cert/domains-verify-plan-editor/cname-record-info.vue +++ b/packages/ui/certd-client/src/components/plugins/cert/domains-verify-plan-editor/cname-record-info.vue @@ -20,7 +20,7 @@ -
不要删除CNAME
+
不要删除CNAME
@@ -37,7 +37,8 @@ const statusDict = dict({ { label: "待设置CNAME", value: "cname", color: "warning" }, { label: "验证中", value: "validating", color: "blue" }, { label: "验证成功", value: "valid", color: "green" }, - { label: "验证失败", value: "failed", color: "red" } + { label: "验证失败", value: "failed", color: "red" }, + { label: "验证超时", value: "timeout", color: "red" } ] }); @@ -67,12 +68,24 @@ function onRecordChange() { }); } +let refreshIntervalId: any = null; async function doRefresh() { if (!props.domain) { return; } cnameRecord.value = await GetByDomain(props.domain); onRecordChange(); + + if (cnameRecord.value.status === "validating") { + if (!refreshIntervalId) { + refreshIntervalId = setInterval(async () => { + await doRefresh(); + }, 9000); + } + } else { + clearInterval(refreshIntervalId); + refreshIntervalId = null; + } } watch( diff --git a/packages/ui/certd-client/src/views/certd/cname/record/crud.tsx b/packages/ui/certd-client/src/views/certd/cname/record/crud.tsx index 9127b8f3..19fe4b26 100644 --- a/packages/ui/certd-client/src/views/certd/cname/record/crud.tsx +++ b/packages/ui/certd-client/src/views/certd/cname/record/crud.tsx @@ -171,7 +171,8 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat { label: "待设置CNAME", value: "cname", color: "warning" }, { label: "验证中", value: "validating", color: "blue" }, { label: "验证成功", value: "valid", color: "green" }, - { label: "验证失败", value: "failed", color: "red" } + { label: "验证失败", value: "failed", color: "red" }, + { label: "验证超时", value: "timeout", color: "red" } ] }), addForm: { @@ -204,7 +205,13 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat if (res === true) { message.success("验证成功"); row.status = "valid"; + } else if (res === false) { + message.success("验证超时"); + row.status = "timeout"; + } else { + message.success("开始验证,请耐心等待"); } + await crudExpose.doRefresh(); } catch (e: any) { console.error(e); message.error(e.message); diff --git a/packages/ui/certd-server/src/modules/cname/entity/cname-record.ts b/packages/ui/certd-server/src/modules/cname/entity/cname-record.ts index 0b137a9a..0328f87f 100644 --- a/packages/ui/certd-server/src/modules/cname/entity/cname-record.ts +++ b/packages/ui/certd-server/src/modules/cname/entity/cname-record.ts @@ -1,5 +1,5 @@ import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm'; -export type CnameRecordStatusType = 'cname' | 'validating' | 'valid' | 'error'; +export type CnameRecordStatusType = 'cname' | 'validating' | 'valid' | 'error' | 'timeout'; /** * cname record配置 */ diff --git a/packages/ui/certd-server/src/modules/cname/service/cname-record-service.ts b/packages/ui/certd-server/src/modules/cname/service/cname-record-service.ts index 92e0d4fd..3ddbe7c9 100644 --- a/packages/ui/certd-server/src/modules/cname/service/cname-record-service.ts +++ b/packages/ui/certd-server/src/modules/cname/service/cname-record-service.ts @@ -4,11 +4,11 @@ import { Repository } from 'typeorm'; import { BaseService, PlusService, ValidateException } from '@certd/lib-server'; import { CnameRecordEntity, CnameRecordStatusType } from '../entity/cname-record.js'; import { createDnsProvider, IDnsProvider, parseDomain } from '@certd/plugin-cert'; -import { CnameProvider } from '@certd/pipeline'; +import { CnameProvider, CnameRecord } from '@certd/pipeline'; import { cache, http, logger, utils } from '@certd/basic'; import { AccessService } from '../../pipeline/service/access-service.js'; -import { isDev } from '../../../utils/env.js'; +import { isDev } from '@certd/basic'; import { walkTxtRecord } from '@certd/acme-client'; import { CnameProviderService } from './cname-provider-service.js'; import { CnameProviderEntity } from '../entity/cname-provider.js'; @@ -128,8 +128,17 @@ export class CnameRecordService extends BaseService { // } async getWithAccessByDomain(domain: string, userId: number) { - const record = await this.getByDomain(domain, userId); - record.cnameProvider.access = await this.accessService.getAccessById(record.cnameProvider.accessId, false); + const record: CnameRecord = await this.getByDomain(domain, userId); + if (record.cnameProvider.id > 0) { + //自定义cname服务 + record.cnameProvider.access = await this.accessService.getAccessById(record.cnameProvider.accessId, false); + } else { + record.commonDnsProvider = new CommonDnsProvider({ + config: record.cnameProvider, + plusService: this.plusService, + }); + } + return record; } @@ -158,7 +167,7 @@ export class CnameRecordService extends BaseService { cnameProvider: { ...provider, } as CnameProvider, - }; + } as CnameRecord; } /** @@ -184,17 +193,20 @@ export class CnameRecordService extends BaseService { startTime: new Date().getTime(), }; } - let ttl = 60 * 60 * 15 * 1000; + let ttl = 15 * 60 * 1000; if (isDev()) { ttl = 30 * 1000; } - const recordValue = bean.recordValue.substring(0, bean.recordValue.indexOf('.')); + const testRecordValue = 'certd-cname-verify'; const buildDnsProvider = async () => { const cnameProvider = await this.cnameProviderService.info(bean.cnameProviderId); if (cnameProvider == null) { throw new ValidateException(`CNAME服务:${bean.cnameProviderId} 已被删除,请修改CNAME记录,重新选择CNAME服务`); } + if (cnameProvider.disabled === true) { + throw new Error(`CNAME服务:${bean.cnameProviderId} 已被禁用`); + } if (cnameProvider.id < 0) { //公共CNAME @@ -218,16 +230,16 @@ export class CnameRecordService extends BaseService { return true; } if (value.startTime + ttl < new Date().getTime()) { - logger.warn(`cname验证超时,停止检查,${bean.domain} ${recordValue}`); + logger.warn(`cname验证超时,停止检查,${bean.domain} ${testRecordValue}`); clearInterval(value.intervalId); - await this.updateStatus(bean.id, 'cname'); + await this.updateStatus(bean.id, 'timeout'); return false; } const originDomain = parseDomain(bean.domain); const fullDomain = `${bean.hostRecord}.${originDomain}`; - logger.info(`检查CNAME配置 ${fullDomain} ${recordValue}`); + logger.info(`检查CNAME配置 ${fullDomain} ${testRecordValue}`); // const txtRecords = await dns.promises.resolveTxt(fullDomain); // if (txtRecords.length) { @@ -240,10 +252,10 @@ export class CnameRecordService extends BaseService { logger.error(`获取TXT记录失败,${e.message}`); } logger.info(`检查到TXT记录 ${JSON.stringify(records)}`); - const success = records.includes(recordValue); + const success = records.includes(testRecordValue); if (success) { clearInterval(value.intervalId); - logger.info(`检测到CNAME配置,修改状态 ${fullDomain} ${recordValue}`); + logger.info(`检测到CNAME配置,修改状态 ${fullDomain} ${testRecordValue}`); await this.updateStatus(bean.id, 'valid'); value.pass = true; cache.delete(cacheKey); @@ -257,8 +269,8 @@ export class CnameRecordService extends BaseService { } catch (e) { logger.error(`删除CNAME的校验DNS记录失败, ${e.message},req:${JSON.stringify(value.recordReq)},recordRes:${JSON.stringify(value.recordRes)}`, e); } + return success; } - return success; }; if (value.validating) { @@ -278,7 +290,7 @@ export class CnameRecordService extends BaseService { fullRecord: fullRecord, hostRecord: hostRecord, type: 'TXT', - value: recordValue, + value: testRecordValue, }; const dnsProvider = await buildDnsProvider(); const recordRes = await dnsProvider.createRecord(req); diff --git a/packages/ui/certd-server/src/modules/cname/service/common-provider.ts b/packages/ui/certd-server/src/modules/cname/service/common-provider.ts index bbbdc30f..c4913074 100644 --- a/packages/ui/certd-server/src/modules/cname/service/common-provider.ts +++ b/packages/ui/certd-server/src/modules/cname/service/common-provider.ts @@ -1,10 +1,10 @@ import { CreateRecordOptions, DnsProviderContext, IDnsProvider, RemoveRecordOptions } from '@certd/plugin-cert'; import { PlusService } from '@certd/lib-server'; -export type CnameProvider = { +export type CommonCnameProvider = { id: number; domain: string; - title: string; + title?: string; }; export const CommonProviders = [ { @@ -16,10 +16,10 @@ export const CommonProviders = [ export class CommonDnsProvider implements IDnsProvider { ctx: DnsProviderContext; - config: CnameProvider; + config: CommonCnameProvider; plusService: PlusService; - constructor(opts: { config: CnameProvider; plusService: PlusService }) { + constructor(opts: { config: CommonCnameProvider; plusService: PlusService }) { this.config = opts.config; this.plusService = opts.plusService; } @@ -34,8 +34,9 @@ export class CommonDnsProvider implements IDnsProvider { const res = await this.plusService.requestWithToken({ url: '/activation/certd/cname/recordCreate', + method: 'post', data: { - subjectId: this.plusService.getSubjectId(), + subjectId: await this.plusService.getSubjectId(), domain: options.domain, hostRecord: options.hostRecord, recordValue: options.value, @@ -47,12 +48,13 @@ export class CommonDnsProvider implements IDnsProvider { async removeRecord(options: RemoveRecordOptions) { const res = await this.plusService.requestWithToken({ url: '/activation/certd/cname/recordRemove', + method: 'post', data: { - subjectId: this.plusService.getSubjectId(), + subjectId: await this.plusService.getSubjectId(), domain: options.recordReq.domain, hostRecord: options.recordReq.hostRecord, recordValue: options.recordReq.value, - recordId: options.recordRes.id, + recordId: options.recordRes.recordId, providerId: this.config.id, }, });