mirror of
https://github.com/certd/certd.git
synced 2026-04-24 04:17:25 +08:00
perf: 检查cname是否正确配置
This commit is contained in:
@@ -58,4 +58,12 @@ export class CnameRecordController extends CrudController<CnameRecordService> {
|
||||
const res = await this.service.getByDomain(body.domain, userId, body.createOnNotFound);
|
||||
return this.ok(res);
|
||||
}
|
||||
|
||||
@Post('/verify', { summary: Constants.per.authOnly })
|
||||
async verify(@Body(ALL) body: { id: string }) {
|
||||
const userId = this.ctx.user.id;
|
||||
await this.service.checkUserId(body.id, userId);
|
||||
const res = await this.service.verify(body.id);
|
||||
return this.ok(res);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
|
||||
|
||||
export type CnameRecordStatusType = 'cname' | 'validating' | 'valid' | 'error';
|
||||
/**
|
||||
* cname record配置
|
||||
*/
|
||||
|
||||
@@ -2,11 +2,14 @@ import { Inject, Provide, Scope, ScopeEnum } from '@midwayjs/core';
|
||||
import { InjectEntityModel } from '@midwayjs/typeorm';
|
||||
import { Repository } from 'typeorm';
|
||||
import { BaseService, ValidateException } from '@certd/lib-server';
|
||||
import { CnameRecordEntity } from '../entity/cname-record.js';
|
||||
import { CnameRecordEntity, CnameRecordStatusType } from '../entity/cname-record.js';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import { CnameProviderService } from '../../sys/cname/service/cname-provider-service.js';
|
||||
import { CnameProviderEntity } from '../../sys/cname/entity/cname_provider.js';
|
||||
import { parseDomain } from '@certd/plugin-cert';
|
||||
import { createDnsProvider, IDnsProvider, parseDomain } from '@certd/plugin-cert';
|
||||
import { cache, http, logger, utils } from '@certd/pipeline';
|
||||
import dns from 'dns';
|
||||
import { AccessService } from '../../pipeline/service/access-service.js';
|
||||
|
||||
/**
|
||||
* 授权
|
||||
@@ -19,6 +22,10 @@ export class CnameRecordService extends BaseService<CnameRecordEntity> {
|
||||
|
||||
@Inject()
|
||||
cnameProviderService: CnameProviderService;
|
||||
|
||||
@Inject()
|
||||
accessService: AccessService;
|
||||
//@ts-ignore
|
||||
getRepository() {
|
||||
return this.repository;
|
||||
}
|
||||
@@ -130,4 +137,81 @@ export class CnameRecordService extends BaseService<CnameRecordEntity> {
|
||||
cnameProvider: provider,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证是否配置好cname
|
||||
* @param id
|
||||
*/
|
||||
async verify(id: string) {
|
||||
const bean = await this.info(id);
|
||||
if (!bean) {
|
||||
throw new ValidateException(`CnameRecord:${id} 不存在`);
|
||||
}
|
||||
const cacheKey = `cname.record.verify.${bean.id}`;
|
||||
|
||||
type CacheValue = {
|
||||
ready: boolean;
|
||||
pass: boolean;
|
||||
};
|
||||
let value: CacheValue = cache.get(cacheKey);
|
||||
if (!value) {
|
||||
value = {
|
||||
ready: false,
|
||||
pass: false,
|
||||
};
|
||||
}
|
||||
|
||||
const originDomain = parseDomain(bean.domain);
|
||||
const fullDomain = `${bean.hostRecord}.${originDomain}`;
|
||||
const recordValue = bean.recordValue.substring(0, bean.recordValue.indexOf('.'));
|
||||
const checkRecordValue = async () => {
|
||||
logger.info(`检查CNAME配置 ${fullDomain} ${recordValue}`);
|
||||
const txtRecords = await dns.promises.resolveTxt(fullDomain);
|
||||
let records: string[] = [];
|
||||
if (txtRecords.length) {
|
||||
records = [].concat(...txtRecords);
|
||||
}
|
||||
logger.info(`检查到TXT记录 ${JSON.stringify(records)}`);
|
||||
const success = records.includes(recordValue);
|
||||
if (success) {
|
||||
logger.info(`检测到CNAME配置,修改状态 ${fullDomain} ${recordValue}`);
|
||||
await this.updateStatus(bean.id, 'valid');
|
||||
value.pass = true;
|
||||
}
|
||||
};
|
||||
|
||||
if (value.ready) {
|
||||
// lookup recordValue in dns
|
||||
return await checkRecordValue();
|
||||
}
|
||||
|
||||
const ttl = 60 * 60 * 30;
|
||||
cache.set(cacheKey, value, {
|
||||
ttl: ttl,
|
||||
});
|
||||
|
||||
const cnameProvider = await this.cnameProviderService.info(bean.cnameProviderId);
|
||||
const access = await this.accessService.getById(cnameProvider.accessId, bean.userId);
|
||||
const context = { access, logger, http, utils };
|
||||
const dnsProvider: IDnsProvider = await createDnsProvider({
|
||||
dnsProviderType: cnameProvider.dnsProviderType,
|
||||
context,
|
||||
});
|
||||
const domain = parseDomain(bean.recordValue);
|
||||
const fullRecord = bean.recordValue;
|
||||
const hostRecord = fullRecord.replace(`.${domain}`, '');
|
||||
const req = {
|
||||
domain: domain,
|
||||
fullRecord: fullRecord,
|
||||
hostRecord: hostRecord,
|
||||
type: 'TXT',
|
||||
value: recordValue,
|
||||
};
|
||||
await dnsProvider.createRecord(req);
|
||||
value.ready = true;
|
||||
}
|
||||
|
||||
async updateStatus(id: number, status: CnameRecordStatusType) {
|
||||
await this.getRepository().update(id, { status });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ export class UserSettingsService extends BaseService<UserSettingsEntity> {
|
||||
@InjectEntityModel(UserSettingsEntity)
|
||||
repository: Repository<UserSettingsEntity>;
|
||||
|
||||
//@ts-ignore
|
||||
getRepository() {
|
||||
return this.repository;
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
import { BaseController } from '@certd/lib-server';
|
||||
import { AccessService } from '../service/access-service.js';
|
||||
import { EmailService } from '../../basic/service/email-service.js';
|
||||
import { AccessGetter } from '../service/access-getter.js';
|
||||
|
||||
@Provide()
|
||||
@Controller('/api/pi/handle')
|
||||
@@ -49,6 +50,7 @@ export class HandleController extends BaseController {
|
||||
|
||||
@Post('/plugin', { summary: Constants.per.authOnly })
|
||||
async pluginRequest(@Body(ALL) body: PluginRequestHandleReq) {
|
||||
const userId = this.getUserId();
|
||||
const pluginDefine = pluginRegistry.get(body.typeName);
|
||||
const pluginCls = pluginDefine.target;
|
||||
if (pluginCls == null) {
|
||||
@@ -59,6 +61,9 @@ export class HandleController extends BaseController {
|
||||
const plugin: PluginRequestHandler = new pluginCls();
|
||||
//@ts-ignore
|
||||
const instance = plugin as ITaskPlugin;
|
||||
|
||||
const accessGetter = new AccessGetter(userId, this.accessService.getById.bind(this.accessService));
|
||||
|
||||
//@ts-ignore
|
||||
const taskCtx: TaskInstanceContext = {
|
||||
pipeline: undefined,
|
||||
@@ -67,7 +72,7 @@ export class HandleController extends BaseController {
|
||||
http,
|
||||
logger: logger,
|
||||
inputChanged: true,
|
||||
accessService: this.accessService,
|
||||
accessService: accessGetter,
|
||||
emailService: this.emailService,
|
||||
pipelineContext: undefined,
|
||||
userContext: undefined,
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
import { ALL, Body, Controller, Inject, Post, Provide, Query } from '@midwayjs/core';
|
||||
import { CrudController } from '@certd/lib-server';
|
||||
import { Constants, CrudController, SysSettingsService } from '@certd/lib-server';
|
||||
import { PipelineService } from '../service/pipeline-service.js';
|
||||
import { PipelineEntity } from '../entity/pipeline.js';
|
||||
import { Constants } from '@certd/lib-server';
|
||||
import { HistoryService } from '../service/history-service.js';
|
||||
import { AuthService } from '../../sys/authority/service/auth-service.js';
|
||||
import { SysSettingsService } from '@certd/lib-server';
|
||||
|
||||
/**
|
||||
* 证书
|
||||
|
||||
@@ -18,6 +18,7 @@ export class AccessService extends BaseService<AccessEntity> {
|
||||
@Inject()
|
||||
encryptService: EncryptService;
|
||||
|
||||
//@ts-ignore
|
||||
getRepository() {
|
||||
return this.repository;
|
||||
}
|
||||
@@ -101,13 +102,13 @@ export class AccessService extends BaseService<AccessEntity> {
|
||||
return await super.update(param);
|
||||
}
|
||||
|
||||
async getById(id: any, userId?: number): Promise<any> {
|
||||
async getById(id: any, userId: number): Promise<any> {
|
||||
const entity = await this.info(id);
|
||||
if (entity == null) {
|
||||
throw new Error(`该授权配置不存在,请确认是否已被删除:id=${id}`);
|
||||
}
|
||||
if (userId !== entity.userId) {
|
||||
throw new PermissionException('您对该授权无访问权限');
|
||||
throw new PermissionException('您对该Access授权无访问权限');
|
||||
}
|
||||
// const access = accessRegistry.get(entity.type);
|
||||
const setting = this.decryptAccessEntity(entity);
|
||||
|
||||
@@ -13,6 +13,7 @@ export class HistoryLogService extends BaseService<HistoryLogEntity> {
|
||||
@InjectEntityModel(HistoryLogEntity)
|
||||
repository: Repository<HistoryLogEntity>;
|
||||
|
||||
//@ts-ignore
|
||||
getRepository() {
|
||||
return this.repository;
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ export class HistoryService extends BaseService<HistoryEntity> {
|
||||
@Config('certd')
|
||||
private certdConfig: any;
|
||||
|
||||
//@ts-ignore
|
||||
getRepository() {
|
||||
return this.repository;
|
||||
}
|
||||
|
||||
@@ -54,6 +54,7 @@ export class PipelineService extends BaseService<PipelineEntity> {
|
||||
@Config('certd')
|
||||
private certdConfig: any;
|
||||
|
||||
//@ts-ignore
|
||||
getRepository() {
|
||||
return this.repository;
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ export class StorageService extends BaseService<StorageEntity> {
|
||||
@InjectEntityModel(StorageEntity)
|
||||
repository: Repository<StorageEntity>;
|
||||
|
||||
//@ts-ignore
|
||||
getRepository() {
|
||||
return this.repository;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { Inject, Provide, Scope, ScopeEnum } from '@midwayjs/core';
|
||||
import { RoleService } from './role-service.js';
|
||||
import { BaseService } from '@certd/lib-server';
|
||||
|
||||
/**
|
||||
* 权限校验
|
||||
@@ -28,7 +27,7 @@ export class AuthService {
|
||||
}
|
||||
}
|
||||
|
||||
async checkEntityUserId(ctx: any, service: BaseService<any>, id: any = 0, userKey = 'userId') {
|
||||
async checkEntityUserId(ctx: any, service: any, id: any = 0, userKey = 'userId') {
|
||||
const isAdmin = await this.isAdmin(ctx);
|
||||
if (isAdmin) {
|
||||
return true;
|
||||
|
||||
@@ -13,6 +13,7 @@ export class PermissionService extends BaseService<PermissionEntity> {
|
||||
@InjectEntityModel(PermissionEntity)
|
||||
repository: Repository<PermissionEntity>;
|
||||
|
||||
//@ts-ignore
|
||||
getRepository() {
|
||||
return this.repository;
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ export class RolePermissionService extends BaseService<RolePermissionEntity> {
|
||||
@InjectEntityModel(RolePermissionEntity)
|
||||
repository: Repository<RolePermissionEntity>;
|
||||
|
||||
//@ts-ignore
|
||||
getRepository() {
|
||||
return this.repository;
|
||||
}
|
||||
|
||||
@@ -29,7 +29,8 @@ export class RoleService extends BaseService<RoleEntity> {
|
||||
ttl: 1000 * 60 * 10,
|
||||
});
|
||||
|
||||
getRepository() {
|
||||
//@ts-ignore
|
||||
getRepository() {
|
||||
return this.repository;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ export class UserRoleService extends BaseService<UserRoleEntity> {
|
||||
@InjectEntityModel(UserRoleEntity)
|
||||
repository: Repository<UserRoleEntity>;
|
||||
|
||||
//@ts-ignore
|
||||
getRepository() {
|
||||
return this.repository;
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ export class UserService extends BaseService<UserEntity> {
|
||||
@Inject()
|
||||
sysSettingsService: SysSettingsService;
|
||||
|
||||
//@ts-ignore
|
||||
getRepository() {
|
||||
return this.repository;
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ export class CnameProviderService extends BaseService<CnameProviderEntity> {
|
||||
@InjectEntityModel(CnameProviderEntity)
|
||||
repository: Repository<CnameProviderEntity>;
|
||||
|
||||
//@ts-ignore
|
||||
getRepository() {
|
||||
return this.repository;
|
||||
}
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
import { ALL, Body, Controller, Get, Inject, Post, Provide } from '@midwayjs/core';
|
||||
import { Constants, SysSettingsService } from '@certd/lib-server';
|
||||
import { BaseController } from '@certd/lib-server';
|
||||
import { AppKey, http, PlusRequestService, verify } from '@certd/pipeline';
|
||||
import { SysInstallInfo } from '@certd/lib-server';
|
||||
import { logger } from '@certd/pipeline';
|
||||
import { PlusService } from '@certd/lib-server';
|
||||
import { BaseController, Constants, PlusService, SysInstallInfo, SysSettingsService } from '@certd/lib-server';
|
||||
import { AppKey, logger, PlusRequestService, verify } from '@certd/pipeline';
|
||||
|
||||
/**
|
||||
*/
|
||||
@@ -63,8 +59,6 @@ export class SysPlusController extends BaseController {
|
||||
const timestamps = 1728365013899;
|
||||
const bindUrl = 'http://89.21.0.171:7001/';
|
||||
const service = new PlusRequestService({
|
||||
logger: logger,
|
||||
http: http,
|
||||
subjectId: subjectId,
|
||||
plusServerBaseUrls: ['https://api.ai.handsfree.work'],
|
||||
});
|
||||
|
||||
+9
-2
@@ -107,16 +107,23 @@ export class AliyunDnsProvider extends AbstractDnsProvider {
|
||||
|
||||
try {
|
||||
const ret = await this.client.request('AddDomainRecord', params, requestOption);
|
||||
this.logger.info('添加域名解析成功:', value, value, ret.RecordId);
|
||||
this.logger.info('添加域名解析成功:', JSON.stringify(options), ret.RecordId);
|
||||
return ret.RecordId;
|
||||
} catch (e: any) {
|
||||
if (e.code === 'DomainRecordDuplicate') {
|
||||
return;
|
||||
}
|
||||
this.logger.info('添加域名解析出错', e);
|
||||
throw e;
|
||||
this.resolveError(e, options);
|
||||
}
|
||||
}
|
||||
|
||||
resolveError(e: any, req: CreateRecordOptions) {
|
||||
if (e.Message.indexOf('The specified domain name does not exist') > -1) {
|
||||
throw new Error(`阿里云账号中不存在此域名:${req.domain}`);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
async removeRecord(options: RemoveRecordOptions<any>): Promise<any> {
|
||||
const { fullRecord, value } = options.recordReq;
|
||||
const record = options.recordRes;
|
||||
|
||||
Reference in New Issue
Block a user