mirror of https://github.com/certd/certd
chore: 优化站点ip检查
parent
a463711b03
commit
41f4617e66
|
@ -136,6 +136,10 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
tabs: {
|
||||||
|
name: "disabled",
|
||||||
|
show: true,
|
||||||
|
},
|
||||||
columns: {
|
columns: {
|
||||||
id: {
|
id: {
|
||||||
title: "ID",
|
title: "ID",
|
||||||
|
@ -210,6 +214,34 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
||||||
show: false,
|
show: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
certInfo: {
|
||||||
|
title: "证书信息",
|
||||||
|
type: "text",
|
||||||
|
form: { show: false },
|
||||||
|
column: {
|
||||||
|
width: 200,
|
||||||
|
sorter: false,
|
||||||
|
show: true,
|
||||||
|
conditionalRender: false,
|
||||||
|
cellRender({ value, row }) {
|
||||||
|
const slots = {
|
||||||
|
content() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div>证书颁发机构:{row.certProvider}</div>
|
||||||
|
<div>证书域名:{row.certDomains}</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<a-popover placement="left" v-slots={slots} overlayStyle={{ maxWidth: "30%" }}>
|
||||||
|
{row.certDomains}
|
||||||
|
</a-popover>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
certDomains: {
|
certDomains: {
|
||||||
title: "证书域名",
|
title: "证书域名",
|
||||||
search: {
|
search: {
|
||||||
|
@ -222,7 +254,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
||||||
column: {
|
column: {
|
||||||
width: 200,
|
width: 200,
|
||||||
sorter: true,
|
sorter: true,
|
||||||
show: true,
|
show: false,
|
||||||
cellRender({ value }) {
|
cellRender({ value }) {
|
||||||
return (
|
return (
|
||||||
<a-tooltip title={value} placement="left">
|
<a-tooltip title={value} placement="left">
|
||||||
|
@ -244,6 +276,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
||||||
column: {
|
column: {
|
||||||
width: 200,
|
width: 200,
|
||||||
sorter: true,
|
sorter: true,
|
||||||
|
show: false,
|
||||||
cellRender({ value }) {
|
cellRender({ value }) {
|
||||||
return <a-tooltip title={value}>{value}</a-tooltip>;
|
return <a-tooltip title={value}>{value}</a-tooltip>;
|
||||||
},
|
},
|
||||||
|
|
|
@ -31,6 +31,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
||||||
|
|
||||||
const addRequest = async (req: AddReq) => {
|
const addRequest = async (req: AddReq) => {
|
||||||
const { form } = req;
|
const { form } = req;
|
||||||
|
form.siteId = context.props.siteId;
|
||||||
const res = await api.AddObj(form);
|
const res = await api.AddObj(form);
|
||||||
return res;
|
return res;
|
||||||
};
|
};
|
||||||
|
|
|
@ -68,8 +68,12 @@ export class SiteInfoController extends CrudController<SiteIpService> {
|
||||||
|
|
||||||
@Post('/delete', { summary: Constants.per.authOnly })
|
@Post('/delete', { summary: Constants.per.authOnly })
|
||||||
async delete(@Query('id') id: number) {
|
async delete(@Query('id') id: number) {
|
||||||
|
const entity = await this.service.info(id);
|
||||||
await this.service.checkUserId(id, this.getUserId());
|
await this.service.checkUserId(id, this.getUserId());
|
||||||
return await super.delete(id);
|
|
||||||
|
const res = await super.delete(id);
|
||||||
|
await this.service.updateIpCount(entity.siteId)
|
||||||
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
@Post('/check', { summary: Constants.per.authOnly })
|
@Post('/check', { summary: Constants.per.authOnly })
|
||||||
|
|
|
@ -13,6 +13,7 @@ import { UserSuiteService } from '@certd/commercial-core';
|
||||||
import { UserSettingsService } from "../../mine/service/user-settings-service.js";
|
import { UserSettingsService } from "../../mine/service/user-settings-service.js";
|
||||||
import { UserSiteMonitorSetting } from "../../mine/service/models.js";
|
import { UserSiteMonitorSetting } from "../../mine/service/models.js";
|
||||||
import {SiteIpService} from "./site-ip-service.js";
|
import {SiteIpService} from "./site-ip-service.js";
|
||||||
|
import {SiteIpEntity} from "../entity/site-ip.js";
|
||||||
|
|
||||||
@Provide()
|
@Provide()
|
||||||
@Scope(ScopeEnum.Request, { allowDowngrade: true })
|
@Scope(ScopeEnum.Request, { allowDowngrade: true })
|
||||||
|
@ -134,9 +135,7 @@ export class SiteInfoService extends BaseService<SiteInfoEntity> {
|
||||||
|
|
||||||
|
|
||||||
//检查ip
|
//检查ip
|
||||||
if( site.ipCheck){
|
await this.checkAllIp(site)
|
||||||
await this.siteIpService.checkAll(site)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!notify) {
|
if (!notify) {
|
||||||
return;
|
return;
|
||||||
|
@ -165,6 +164,43 @@ export class SiteInfoService extends BaseService<SiteInfoEntity> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async checkAllIp(site:SiteInfoEntity){
|
||||||
|
if( !site.ipCheck){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const certExpiresTime = site.certExpiresTime;
|
||||||
|
const onFinished = async (list:SiteIpEntity[])=>{
|
||||||
|
let errorCount = 0
|
||||||
|
let errorMessage = ""
|
||||||
|
for (const item of list) {
|
||||||
|
errorCount++
|
||||||
|
if(item.error){
|
||||||
|
errorMessage += `${item.ipAddress}:${item.error}; \n`
|
||||||
|
}else if(item.certExpiresTime!==certExpiresTime){
|
||||||
|
errorMessage += `${item.ipAddress}:与主站证书过期时间不一致; \n`
|
||||||
|
}else{
|
||||||
|
errorCount--
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (errorCount<=0){
|
||||||
|
return
|
||||||
|
}
|
||||||
|
await this.update({
|
||||||
|
id: site.id,
|
||||||
|
checkStatus: 'error',
|
||||||
|
error: errorMessage,
|
||||||
|
ipErrorCount: errorCount,
|
||||||
|
})
|
||||||
|
try {
|
||||||
|
site = await this.info(site.id)
|
||||||
|
await this.sendCheckErrorNotify(site,true);
|
||||||
|
} catch (e) {
|
||||||
|
logger.error('send notify error', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await this.siteIpService.checkAll(site,onFinished)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 检查
|
* 检查
|
||||||
* @param id
|
* @param id
|
||||||
|
@ -179,7 +215,7 @@ export class SiteInfoService extends BaseService<SiteInfoEntity> {
|
||||||
return await this.doCheck(site, notify, retryTimes);
|
return await this.doCheck(site, notify, retryTimes);
|
||||||
}
|
}
|
||||||
|
|
||||||
async sendCheckErrorNotify(site: SiteInfoEntity) {
|
async sendCheckErrorNotify(site: SiteInfoEntity,fromIpCheck=false) {
|
||||||
const url = await this.notificationService.getBindUrl('#/certd/monitor/site');
|
const url = await this.notificationService.getBindUrl('#/certd/monitor/site');
|
||||||
// 发邮件
|
// 发邮件
|
||||||
await this.notificationService.send(
|
await this.notificationService.send(
|
||||||
|
@ -188,8 +224,9 @@ export class SiteInfoService extends BaseService<SiteInfoEntity> {
|
||||||
logger: logger,
|
logger: logger,
|
||||||
body: {
|
body: {
|
||||||
url,
|
url,
|
||||||
title: `站点证书检查出错<${site.name}>`,
|
title: `站点证书${fromIpCheck?"(IP)":""}检查出错<${site.name}>`,
|
||||||
content: `站点名称: ${site.name} \n站点域名: ${site.domain} \n错误信息:${site.error}`,
|
content: `站点名称: ${site.name} \n站点域名: ${site.domain} \n错误信息:${site.error}`,
|
||||||
|
errorMessage: site.error,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
site.userId
|
site.userId
|
||||||
|
@ -227,6 +264,7 @@ export class SiteInfoService extends BaseService<SiteInfoEntity> {
|
||||||
title: `站点证书已过期${-validDays}天<${site.name}>`,
|
title: `站点证书已过期${-validDays}天<${site.name}>`,
|
||||||
content,
|
content,
|
||||||
url,
|
url,
|
||||||
|
errorMessage: "站点证书已过期"
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
site.userId
|
site.userId
|
||||||
|
@ -272,4 +310,5 @@ export class SiteInfoService extends BaseService<SiteInfoEntity> {
|
||||||
await this.siteIpService.sync(site)
|
await this.siteIpService.sync(site)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,8 @@ import {PeerCertificate} from "tls";
|
||||||
export class SiteIpService extends BaseService<SiteIpEntity> {
|
export class SiteIpService extends BaseService<SiteIpEntity> {
|
||||||
@InjectEntityModel(SiteIpEntity)
|
@InjectEntityModel(SiteIpEntity)
|
||||||
repository: Repository<SiteIpEntity>;
|
repository: Repository<SiteIpEntity>;
|
||||||
|
@InjectEntityModel(SiteInfoEntity)
|
||||||
|
siteInfoRepository: Repository<SiteInfoEntity>;
|
||||||
|
|
||||||
@Inject()
|
@Inject()
|
||||||
notificationService: NotificationService;
|
notificationService: NotificationService;
|
||||||
|
@ -36,14 +38,17 @@ export class SiteIpService extends BaseService<SiteIpEntity> {
|
||||||
return this.repository;
|
return this.repository;
|
||||||
}
|
}
|
||||||
|
|
||||||
async add(data: SiteInfoEntity) {
|
async add(data: SiteIpEntity) {
|
||||||
if (!data.userId) {
|
if (!data.userId) {
|
||||||
throw new Error("userId is required");
|
throw new Error("userId is required");
|
||||||
}
|
}
|
||||||
data.disabled = false;
|
data.disabled = false;
|
||||||
return await super.add(data);
|
const res= await super.add(data);
|
||||||
|
await this.updateIpCount(data.siteId)
|
||||||
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async update(data: any) {
|
async update(data: any) {
|
||||||
if (!data.id) {
|
if (!data.id) {
|
||||||
throw new Error("id is required");
|
throw new Error("id is required");
|
||||||
|
@ -80,7 +85,7 @@ export class SiteIpService extends BaseService<SiteIpEntity> {
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.checkAll(entity);
|
await this.checkAll(entity);
|
||||||
|
await this.updateIpCount(entity.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
async check(ipId: number, domain: string, port: number) {
|
async check(ipId: number, domain: string, port: number) {
|
||||||
|
@ -131,6 +136,8 @@ export class SiteIpService extends BaseService<SiteIpEntity> {
|
||||||
|
|
||||||
await this.update(updateData);
|
await this.update(updateData);
|
||||||
|
|
||||||
|
return updateData
|
||||||
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error("check site ip error", e);
|
logger.error("check site ip error", e);
|
||||||
await this.update({
|
await this.update({
|
||||||
|
@ -139,10 +146,15 @@ export class SiteIpService extends BaseService<SiteIpEntity> {
|
||||||
lastCheckTime: dayjs().valueOf(),
|
lastCheckTime: dayjs().valueOf(),
|
||||||
error: e.message
|
error: e.message
|
||||||
});
|
});
|
||||||
|
return {
|
||||||
|
id: entity.id,
|
||||||
|
ipAddress: entity.ipAddress,
|
||||||
|
error: e.message
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async checkAll(siteInfo: SiteInfoEntity) {
|
async checkAll(siteInfo: SiteInfoEntity,onFinish?: (e: any) => void) {
|
||||||
const siteId = siteInfo.id;
|
const siteId = siteInfo.id;
|
||||||
const ips = await this.repository.find({
|
const ips = await this.repository.find({
|
||||||
where: {
|
where: {
|
||||||
|
@ -152,17 +164,28 @@ export class SiteIpService extends BaseService<SiteIpEntity> {
|
||||||
const domain = siteInfo.domain;
|
const domain = siteInfo.domain;
|
||||||
const port = siteInfo.httpsPort;
|
const port = siteInfo.httpsPort;
|
||||||
const promiseList = [];
|
const promiseList = [];
|
||||||
for (const ip of ips) {
|
for (const item of ips) {
|
||||||
const func = async () => {
|
const func = async () => {
|
||||||
try {
|
try {
|
||||||
await this.check(ip.id, domain, port);
|
return await this.check(item.id, domain, port);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error("check site ip error", e);
|
logger.error("check site item error", e);
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
error:e.message
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
promiseList.push(func());
|
promiseList.push(func());
|
||||||
}
|
}
|
||||||
Promise.all(promiseList);
|
Promise.all(promiseList).then((res)=>{
|
||||||
|
const finished = res.filter(item=>{
|
||||||
|
return item
|
||||||
|
})
|
||||||
|
if (finished.length > 0) {
|
||||||
|
onFinish && onFinish(finished)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async getAllIpsFromDomain(domain: string) {
|
async getAllIpsFromDomain(domain: string) {
|
||||||
|
@ -192,4 +215,21 @@ export class SiteIpService extends BaseService<SiteIpEntity> {
|
||||||
return [...res[0], ...res[1]];
|
return [...res[0], ...res[1]];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async updateIpCount(siteId:number){
|
||||||
|
const count = await this.repository.count({
|
||||||
|
where:{
|
||||||
|
siteId
|
||||||
|
}
|
||||||
|
})
|
||||||
|
await this.siteInfoRepository.update({
|
||||||
|
//where
|
||||||
|
id:siteId,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
//update
|
||||||
|
ipCount:count
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue