diff --git a/packages/ui/certd-client/src/locales/langs/en-US/certd.ts b/packages/ui/certd-client/src/locales/langs/en-US/certd.ts index 4c949b63a..018da9e1d 100644 --- a/packages/ui/certd-client/src/locales/langs/en-US/certd.ts +++ b/packages/ui/certd-client/src/locales/langs/en-US/certd.ts @@ -282,6 +282,9 @@ export default { disabled: "Enable/Disable", ipCheck: "Enable IP Check", ipSyncAuto: "Enable IP Sync Auto", + ipSyncMode: "IP Sync Mode", + ipIgnoreCoherence: "Ignore Certificate Coherence", + ipIgnoreCoherenceHelper: "Enable to ignore certificate coherence check, only check certificate expiration time", selectRequired: "Please select", ipCheckConfirm: "Are you sure to {status} IP check?", ipCount: "IP Count", diff --git a/packages/ui/certd-client/src/locales/langs/zh-CN/certd.ts b/packages/ui/certd-client/src/locales/langs/zh-CN/certd.ts index 02e874e5b..17030ec5b 100644 --- a/packages/ui/certd-client/src/locales/langs/zh-CN/certd.ts +++ b/packages/ui/certd-client/src/locales/langs/zh-CN/certd.ts @@ -286,9 +286,16 @@ export default { disabled: "禁用启用", ipCheck: "开启IP检查", ipSyncAuto: "自动同步IP", + ipSyncMode: "IP同步模式", + ipSyncModeHelper: "选择仅检查IPv4或IPv6,或检查所有IP", + ipSyncModeAll: "检查所有IP", + ipSyncModeIPV4Only: "仅检查IPv4", + ipSyncModeIPV6Only: "仅检查IPv6", selectRequired: "请选择", ipCheckConfirm: "确定{status}IP检查?", ipCount: "IP数量", + ipIgnoreCoherence: "忽略证书一致性", + ipIgnoreCoherenceHelper: "开启后,即使IP上的证书与站点证书不一致,也会被认为是正常,仅校验证书过期时间", checkStatus: "检查状态", pipelineId: "关联流水线ID", certInfoId: "证书ID", diff --git a/packages/ui/certd-client/src/views/certd/addon/addon-selector/index.vue b/packages/ui/certd-client/src/views/certd/addon/addon-selector/index.vue index 61776a66f..e7e75e6eb 100644 --- a/packages/ui/certd-client/src/views/certd/addon/addon-selector/index.vue +++ b/packages/ui/certd-client/src/views/certd/addon/addon-selector/index.vue @@ -148,7 +148,6 @@ async function refreshTarget(value: any) { type: "", }; } - debugger } watch( diff --git a/packages/ui/certd-client/src/views/certd/monitor/site/crud.tsx b/packages/ui/certd-client/src/views/certd/monitor/site/crud.tsx index f48fca630..713c6b5ec 100644 --- a/packages/ui/certd-client/src/views/certd/monitor/site/crud.tsx +++ b/packages/ui/certd-client/src/views/certd/monitor/site/crud.tsx @@ -610,6 +610,46 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat }, }, }, + checkStatus: { + title: t("certd.monitor.checkStatus"), + search: { + show: false, + }, + type: "dict-select", + dict: checkStatusDict, + form: { + show: false, + }, + column: { + width: 100, + align: "center", + sorter: true, + cellRender({ value, row }) { + return ( + + + + ); + }, + }, + }, + // error: { + // title: "错误信息", + // search: { + // show: false + // }, + // type: "text", + // form: { + // show: false + // }, + // column: { + // width: 200, + // sorter: true, + // cellRender({ value }) { + // return {value}; + // } + // } + // }, ipCheck: { title: t("certd.monitor.ipCheck"), type: "dict-switch", @@ -672,46 +712,51 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat align: "center", }, }, - checkStatus: { - title: t("certd.monitor.checkStatus"), - search: { - show: false, - }, + ipSyncMode: { + title: t("certd.monitor.ipSyncMode"), type: "dict-select", - dict: checkStatusDict, + dict: dict({ + data: [ + { label: t("certd.monitor.ipSyncModeAll"), value: "all" }, + { label: t("certd.monitor.ipSyncModeIPV4Only"), value: "ipv4" }, + { label: t("certd.monitor.ipSyncModeIPV6Only"), value: "ipv6" }, + ], + }), form: { - show: false, + value: "all", + show: compute(({ form }) => { + return form.ipSyncAuto; + }), + helper: t("certd.monitor.ipSyncModeHelper"), }, column: { width: 100, - align: "center", sorter: true, - cellRender({ value, row }) { - return ( - - - - ); - }, + align: "center", + }, + }, + ipIgnoreCoherence: { + title: t("certd.monitor.ipIgnoreCoherence"), + type: "dict-switch", + dict: dict({ + data: [ + { label: t("common.enabled"), value: true, color: "green" }, + { label: t("common.disabled"), value: false, color: "gray" }, + ], + }), + form: { + value: false, + show: compute(({ form }) => { + return form.ipCheck; + }), + helper: t("certd.monitor.ipIgnoreCoherenceHelper"), + }, + column: { + width: 100, + sorter: true, + align: "center", }, }, - // error: { - // title: "错误信息", - // search: { - // show: false - // }, - // type: "text", - // form: { - // show: false - // }, - // column: { - // width: 200, - // sorter: true, - // cellRender({ value }) { - // return {value}; - // } - // } - // }, pipelineId: { title: t("certd.monitor.pipelineId"), search: { diff --git a/packages/ui/certd-server/db/migration/v10036__ipcheck.sql b/packages/ui/certd-server/db/migration/v10036__ipcheck.sql index 49ed5882a..8553f3251 100644 --- a/packages/ui/certd-server/db/migration/v10036__ipcheck.sql +++ b/packages/ui/certd-server/db/migration/v10036__ipcheck.sql @@ -1,4 +1,6 @@ -ALTER TABLE cd_site_info ADD COLUMN ip_sync_auto boolean DEFAULT (1); +ALTER TABLE cd_site_info ADD COLUMN ip_sync_auto boolean; +ALTER TABLE cd_site_info ADD COLUMN ip_sync_mode varchar(20); +ALTER TABLE cd_site_info ADD COLUMN ip_ignore_coherence boolean; ALTER TABLE pi_pipeline ADD COLUMN webhook_key varchar(100); ALTER TABLE pi_pipeline ADD COLUMN trigger_count integer DEFAULT (0); diff --git a/packages/ui/certd-server/src/controller/user/monitor/site-info-controller.ts b/packages/ui/certd-server/src/controller/user/monitor/site-info-controller.ts index 4431c5b8b..4ebda0274 100644 --- a/packages/ui/certd-server/src/controller/user/monitor/site-info-controller.ts +++ b/packages/ui/certd-server/src/controller/user/monitor/site-info-controller.ts @@ -5,6 +5,7 @@ import { SiteInfoService } from "../../../modules/monitor/service/site-info-serv import { UserSiteMonitorSetting } from "../../../modules/mine/service/models.js"; import { merge } from "lodash-es"; import {SiteIpService} from "../../../modules/monitor/service/site-ip-service.js"; +import { utils } from "@certd/basic"; /** */ @@ -104,6 +105,7 @@ export class SiteInfoController extends CrudController { async check(@Body('id') id: number) { await this.service.checkUserId(id, this.getUserId()); await this.service.check(id, true, 0); + await utils.sleep(1000); return this.ok(); } diff --git a/packages/ui/certd-server/src/modules/monitor/entity/site-info.ts b/packages/ui/certd-server/src/modules/monitor/entity/site-info.ts index 36591f6a5..298ffe193 100644 --- a/packages/ui/certd-server/src/modules/monitor/entity/site-info.ts +++ b/packages/ui/certd-server/src/modules/monitor/entity/site-info.ts @@ -49,6 +49,12 @@ export class SiteInfoEntity { @Column({ name: 'ip_sync_auto', comment: '是否自动同步IP' }) ipSyncAuto: boolean; + @Column({ name: 'ip_sync_mode', comment: 'IP同步模式' }) + ipSyncMode: string; + + @Column({ name: 'ip_ignore_coherence', comment: '忽略证书一致性' }) + ipIgnoreCoherence: boolean; + @Column({ name: 'ip_count', comment: 'ip数量' }) ipCount: number diff --git a/packages/ui/certd-server/src/modules/monitor/service/site-info-service.ts b/packages/ui/certd-server/src/modules/monitor/service/site-info-service.ts index 5aae1cf71..42f886a28 100644 --- a/packages/ui/certd-server/src/modules/monitor/service/site-info-service.ts +++ b/packages/ui/certd-server/src/modules/monitor/service/site-info-service.ts @@ -162,16 +162,16 @@ export class SiteInfoService extends BaseService { } await this.update(updateData); - + const setting = await this.userSettingsService.getSetting(site.userId, UserSiteMonitorSetting) //检查ip - await this.checkAllIp(site,retryTimes); + await this.checkAllIp(site,retryTimes,setting); if (!notify) { return; } try { - await this.sendExpiresNotify(site.id); + await this.sendExpiresNotify(site.id,setting); } catch (e) { logger.error("send notify error", e); } @@ -187,18 +187,19 @@ export class SiteInfoService extends BaseService { return; } try { - await this.sendCheckErrorNotify(site.id); + await this.sendCheckErrorNotify(site.id,false,setting); } catch (e) { logger.error("send notify error", e); } } } - async checkAllIp(site: SiteInfoEntity,retryTimes = null) { + async checkAllIp(site: SiteInfoEntity,retryTimes = null,setting: UserSiteMonitorSetting) { if (!site.ipCheck) { return; } const certExpiresTime = site.certExpiresTime; + const tipDays = setting?.certValidDays || 10; const onFinished = async (list: SiteIpEntity[]) => { let errorCount = 0; let errorMessage = ""; @@ -207,11 +208,19 @@ export class SiteInfoService extends BaseService { continue; } errorCount++; + + const isExpired = dayjs().valueOf() > dayjs(item.certExpiresTime).valueOf(); + const isWillExpired = dayjs().valueOf() > dayjs(item.certExpiresTime).subtract(tipDays, "day").valueOf(); + if (item.error) { errorMessage += `${item.ipAddress}:${item.error}; \n`; - } else if (item.certExpiresTime !== certExpiresTime) { + } else if (item.certExpiresTime !== certExpiresTime && !site.ipIgnoreCoherence) { errorMessage += `${item.ipAddress}:与主站证书过期时间不一致(主站:${dayjs(certExpiresTime).format("YYYY-MM-DD")},IP:${dayjs(item.certExpiresTime).format("YYYY-MM-DD")}); \n`; - } else { + } else if (isExpired){ + errorMessage += `${item.ipAddress}:证书已过期(过期时间:${dayjs(item.certExpiresTime).format("YYYY-MM-DD")}); \n`; + }else if (isWillExpired){ + errorMessage += `${item.ipAddress}:证书将过期(过期时间:${dayjs(item.certExpiresTime).format("YYYY-MM-DD")}); \n`; + }else { errorCount--; } } @@ -232,12 +241,12 @@ export class SiteInfoService extends BaseService { ipErrorCount: errorCount }); try { - await this.sendCheckErrorNotify(site.id, true); + await this.sendCheckErrorNotify(site.id, true,setting); } catch (e) { logger.error("send notify error", e); } }; - if (!site.ipSyncAuto) { + if (site.ipSyncAuto === false) { await this.siteIpService.checkAll(site, retryTimes,onFinished); }else{ await this.siteIpService.syncAndCheck(site, retryTimes,onFinished); @@ -246,7 +255,7 @@ export class SiteInfoService extends BaseService { } /** - * 检查 + * 检查,不等待返回 * @param id * @param notify * @param retryTimes @@ -256,13 +265,16 @@ export class SiteInfoService extends BaseService { if (!site) { throw new Error("站点不存在"); } - return await this.doCheck(site, notify, retryTimes); + + this.doCheck(site, notify, retryTimes).catch((err) => { + logger.error("check site error", err); + }); + return } - async sendCheckErrorNotify(siteId: number, fromIpCheck = false) { + async sendCheckErrorNotify(siteId: number, fromIpCheck = false,setting: UserSiteMonitorSetting) { const site = await this.info(siteId); const url = await this.notificationService.getBindUrl("#/certd/monitor/site"); - const setting = await this.userSettingsService.getSetting(site.userId, UserSiteMonitorSetting) // 发邮件 await this.notificationService.send( { @@ -281,11 +293,9 @@ export class SiteInfoService extends BaseService { ); } - async sendExpiresNotify(siteId: number) { - const site = await this.info(siteId); - const setting = await this.userSettingsService.getSetting(site.userId, UserSiteMonitorSetting) + async sendExpiresNotify(siteId: number,setting: UserSiteMonitorSetting) { const tipDays = setting?.certValidDays || 10; - + const site = await this.info(siteId); const expires = site.certExpiresTime; const validDays = dayjs(expires).diff(dayjs(), "day"); const url = await this.notificationService.getBindUrl("#/certd/monitor/site"); diff --git a/packages/ui/certd-server/src/modules/monitor/service/site-ip-service.ts b/packages/ui/certd-server/src/modules/monitor/service/site-ip-service.ts index eb005d539..6d4eb6157 100644 --- a/packages/ui/certd-server/src/modules/monitor/service/site-ip-service.ts +++ b/packages/ui/certd-server/src/modules/monitor/service/site-ip-service.ts @@ -76,7 +76,7 @@ export class SiteIpService extends BaseService { } //从域名解析中获取所有ip - const ips = await this.getAllIpsFromDomain(domain,resolver); + const ips = await this.getAllIpsFromDomain(domain,resolver,entity.ipSyncMode); if (ips.length === 0 ) { logger.warn(`没有发现${domain}的IP`) return @@ -126,7 +126,7 @@ export class SiteIpService extends BaseService { } } - async check(ipId: number, domain: string, port: number,retryTimes = null) { + async check(ipId: number, domain: string, port: number,retryTimes = null ,tipDays = 10) { if(!ipId){ return } @@ -231,7 +231,7 @@ export class SiteIpService extends BaseService { }) } - async getAllIpsFromDomain(domain: string,resolver:any = dns):Promise { + async getAllIpsFromDomain(domain: string,resolver:any = dns,ipSyncMode:string = "all"):Promise { const getFromV4 = async ():Promise => { try{ return await resolver.resolve4(domain); @@ -249,6 +249,12 @@ export class SiteIpService extends BaseService { } } + if (ipSyncMode === "ipv4") { + return await getFromV4(); + } + if (ipSyncMode === "ipv6") { + return await getFromV6(); + } return Promise.all([getFromV4(), getFromV6()]).then(res => { return [...res[0], ...res[1]];