mirror of https://github.com/certd/certd
fix: 修复cname服务普通用户access访问权限问题
parent
e8b5fcf3ee
commit
c1e3e2ee1f
|
@ -16,6 +16,7 @@ export type AccessDefine = Registrable & {
|
||||||
};
|
};
|
||||||
export interface IAccessService {
|
export interface IAccessService {
|
||||||
getById<T = any>(id: any): Promise<T>;
|
getById<T = any>(id: any): Promise<T>;
|
||||||
|
getCommonById<T = any>(id: any): Promise<T>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IAccess {
|
export interface IAccess {
|
||||||
|
|
|
@ -1,9 +1,13 @@
|
||||||
|
import { IAccess } from "../access";
|
||||||
|
|
||||||
export type CnameProvider = {
|
export type CnameProvider = {
|
||||||
id: any;
|
id: any;
|
||||||
domain: string;
|
domain: string;
|
||||||
dnsProviderType: string;
|
dnsProviderType: string;
|
||||||
|
access?: IAccess;
|
||||||
accessId: any;
|
accessId: any;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type CnameRecord = {
|
export type CnameRecord = {
|
||||||
id: any;
|
id: any;
|
||||||
domain: string;
|
domain: string;
|
||||||
|
|
|
@ -266,7 +266,7 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
|
||||||
eab = await this.ctx.accessService.getById(this.eabAccessId);
|
eab = await this.ctx.accessService.getById(this.eabAccessId);
|
||||||
} else if (this.googleCommonEabAccessId) {
|
} else if (this.googleCommonEabAccessId) {
|
||||||
this.logger.info("当前正在使用 google公共EAB授权");
|
this.logger.info("当前正在使用 google公共EAB授权");
|
||||||
eab = await this.ctx.accessService.getById(this.googleCommonEabAccessId);
|
eab = await this.ctx.accessService.getCommonById(this.googleCommonEabAccessId);
|
||||||
} else {
|
} else {
|
||||||
this.logger.error("google需要配置EAB授权或服务账号授权");
|
this.logger.error("google需要配置EAB授权或服务账号授权");
|
||||||
return;
|
return;
|
||||||
|
@ -277,7 +277,7 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
|
||||||
eab = await this.ctx.accessService.getById(this.eabAccessId);
|
eab = await this.ctx.accessService.getById(this.eabAccessId);
|
||||||
} else if (this.zerosslCommonEabAccessId) {
|
} else if (this.zerosslCommonEabAccessId) {
|
||||||
this.logger.info("当前正在使用 zerossl 公共EAB授权");
|
this.logger.info("当前正在使用 zerossl 公共EAB授权");
|
||||||
eab = await this.ctx.accessService.getById(this.zerosslCommonEabAccessId);
|
eab = await this.ctx.accessService.getCommonById(this.zerosslCommonEabAccessId);
|
||||||
} else {
|
} else {
|
||||||
this.logger.error("zerossl需要配置EAB授权");
|
this.logger.error("zerossl需要配置EAB授权");
|
||||||
return;
|
return;
|
||||||
|
@ -324,8 +324,8 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
|
||||||
domainsVerifyPlan = await this.createDomainsVerifyPlan();
|
domainsVerifyPlan = await this.createDomainsVerifyPlan();
|
||||||
} else {
|
} else {
|
||||||
const dnsProviderType = this.dnsProviderType;
|
const dnsProviderType = this.dnsProviderType;
|
||||||
const dnsProviderAccessId = this.dnsProviderAccess;
|
const access = await this.ctx.accessService.getById(this.dnsProviderAccess);
|
||||||
dnsProvider = await this.createDnsProvider(dnsProviderType, dnsProviderAccessId);
|
dnsProvider = await this.createDnsProvider(dnsProviderType, access);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -351,9 +351,8 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async createDnsProvider(dnsProviderType: string, dnsProviderAccessId: number): Promise<IDnsProvider> {
|
async createDnsProvider(dnsProviderType: string, dnsProviderAccess: any): Promise<IDnsProvider> {
|
||||||
const access = await this.accessService.getById(dnsProviderAccessId);
|
const context: DnsProviderContext = { access: dnsProviderAccess, logger: this.logger, http: this.ctx.http, utils };
|
||||||
const context: DnsProviderContext = { access, logger: this.logger, http: this.ctx.http, utils };
|
|
||||||
return await createDnsProvider({
|
return await createDnsProvider({
|
||||||
dnsProviderType,
|
dnsProviderType,
|
||||||
context,
|
context,
|
||||||
|
@ -367,14 +366,15 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
|
||||||
let dnsProvider = null;
|
let dnsProvider = null;
|
||||||
const cnameVerifyPlan: Record<string, CnameVerifyPlan> = {};
|
const cnameVerifyPlan: Record<string, CnameVerifyPlan> = {};
|
||||||
if (domainVerifyPlan.type === "dns") {
|
if (domainVerifyPlan.type === "dns") {
|
||||||
dnsProvider = await this.createDnsProvider(domainVerifyPlan.dnsProviderType, domainVerifyPlan.dnsProviderAccessId);
|
const access = await this.ctx.accessService.getById(domainVerifyPlan.dnsProviderAccessId);
|
||||||
|
dnsProvider = await this.createDnsProvider(domainVerifyPlan.dnsProviderType, access);
|
||||||
} else {
|
} else {
|
||||||
for (const key in domainVerifyPlan.cnameVerifyPlan) {
|
for (const key in domainVerifyPlan.cnameVerifyPlan) {
|
||||||
const cnameRecord = await this.ctx.cnameProxyService.getByDomain(key);
|
const cnameRecord = await this.ctx.cnameProxyService.getByDomain(key);
|
||||||
cnameVerifyPlan[key] = {
|
cnameVerifyPlan[key] = {
|
||||||
domain: cnameRecord.cnameProvider.domain,
|
domain: cnameRecord.cnameProvider.domain,
|
||||||
fullRecord: cnameRecord.recordValue,
|
fullRecord: cnameRecord.recordValue,
|
||||||
dnsProvider: await this.createDnsProvider(cnameRecord.cnameProvider.dnsProviderType, cnameRecord.cnameProvider.accessId),
|
dnsProvider: await this.createDnsProvider(cnameRecord.cnameProvider.dnsProviderType, cnameRecord.cnameProvider.access),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -130,7 +130,6 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
||||||
component: {
|
component: {
|
||||||
name: "access-selector",
|
name: "access-selector",
|
||||||
vModel: "modelValue",
|
vModel: "modelValue",
|
||||||
from: "sys",
|
|
||||||
type: compute(({ form }) => {
|
type: compute(({ form }) => {
|
||||||
return form.dnsProviderType;
|
return form.dnsProviderType;
|
||||||
})
|
})
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
ALTER TABLE cd_cname_provider ADD COLUMN user_id integer;
|
||||||
|
|
||||||
|
update cd_cname_provider set user_id = 1;
|
||||||
|
|
|
@ -34,11 +34,13 @@ export class CnameRecordController extends CrudController<CnameProviderService>
|
||||||
disabled: false,
|
disabled: false,
|
||||||
};
|
};
|
||||||
merge(bean, def);
|
merge(bean, def);
|
||||||
|
bean.userId = this.getUserId();
|
||||||
return super.add(bean);
|
return super.add(bean);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Post('/update', { summary: 'sys:settings:edit' })
|
@Post('/update', { summary: 'sys:settings:edit' })
|
||||||
async update(@Body(ALL) bean: any) {
|
async update(@Body(ALL) bean: any) {
|
||||||
|
bean.userId = this.getUserId();
|
||||||
return super.update(bean);
|
return super.update(bean);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,8 @@ import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
|
||||||
export class CnameProviderEntity {
|
export class CnameProviderEntity {
|
||||||
@PrimaryGeneratedColumn()
|
@PrimaryGeneratedColumn()
|
||||||
id: number;
|
id: number;
|
||||||
|
@Column({ comment: 'userId', name: 'user_id' })
|
||||||
|
userId: number;
|
||||||
@Column({ comment: '域名', length: 100 })
|
@Column({ comment: '域名', length: 100 })
|
||||||
domain: string;
|
domain: string;
|
||||||
@Column({ comment: 'DNS提供商类型', name: 'dns_provider_type', length: 20 })
|
@Column({ comment: 'DNS提供商类型', name: 'dns_provider_type', length: 20 })
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { BaseService, ValidateException } from '@certd/lib-server';
|
||||||
import { CnameRecordEntity, CnameRecordStatusType } from '../entity/cname-record.js';
|
import { CnameRecordEntity, CnameRecordStatusType } from '../entity/cname-record.js';
|
||||||
import { v4 as uuidv4 } from 'uuid';
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
import { createDnsProvider, IDnsProvider, parseDomain } from '@certd/plugin-cert';
|
import { createDnsProvider, IDnsProvider, parseDomain } from '@certd/plugin-cert';
|
||||||
import { cache, http, logger, utils } from '@certd/pipeline';
|
import { cache, CnameProvider, http, logger, utils } from '@certd/pipeline';
|
||||||
import { AccessService } from '../../pipeline/service/access-service.js';
|
import { AccessService } from '../../pipeline/service/access-service.js';
|
||||||
import { isDev } from '../../../utils/env.js';
|
import { isDev } from '../../../utils/env.js';
|
||||||
import { walkTxtRecord } from '@certd/acme-client';
|
import { walkTxtRecord } from '@certd/acme-client';
|
||||||
|
@ -109,16 +109,22 @@ export class CnameRecordService extends BaseService<CnameRecordEntity> {
|
||||||
return await super.update(param);
|
return await super.update(param);
|
||||||
}
|
}
|
||||||
|
|
||||||
async validate(id: number) {
|
// async validate(id: number) {
|
||||||
const info = await this.info(id);
|
// const info = await this.info(id);
|
||||||
if (info.status === 'success') {
|
// if (info.status === 'success') {
|
||||||
return true;
|
// return true;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
|
// //开始校验
|
||||||
|
// // 1. dnsProvider
|
||||||
|
// // 2. 添加txt记录
|
||||||
|
// // 3. 检查原域名是否有cname记录
|
||||||
|
// }
|
||||||
|
|
||||||
//开始校验
|
async getWithAccessByDomain(domain: string, userId: number) {
|
||||||
// 1. dnsProvider
|
const record = await this.getByDomain(domain, userId);
|
||||||
// 2. 添加txt记录
|
record.cnameProvider.access = await this.accessService.getAccessById(record.cnameProvider.accessId, false);
|
||||||
// 3. 检查原域名是否有cname记录
|
return record;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getByDomain(domain: string, userId: number, createOnNotFound = true) {
|
async getByDomain(domain: string, userId: number, createOnNotFound = true) {
|
||||||
|
@ -143,7 +149,9 @@ export class CnameRecordService extends BaseService<CnameRecordEntity> {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...record,
|
...record,
|
||||||
cnameProvider: provider,
|
cnameProvider: {
|
||||||
|
...provider,
|
||||||
|
} as CnameProvider,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,7 +186,10 @@ export class CnameRecordService extends BaseService<CnameRecordEntity> {
|
||||||
|
|
||||||
const buildDnsProvider = async () => {
|
const buildDnsProvider = async () => {
|
||||||
const cnameProvider = await this.cnameProviderService.info(bean.cnameProviderId);
|
const cnameProvider = await this.cnameProviderService.info(bean.cnameProviderId);
|
||||||
const access = await this.accessService.getById(cnameProvider.accessId, bean.userId);
|
if (cnameProvider == null) {
|
||||||
|
throw new ValidateException(`CNAME服务:${bean.cnameProviderId} 已被删除,请修改CNAME记录,重新选择CNAME服务`);
|
||||||
|
}
|
||||||
|
const access = await this.accessService.getById(cnameProvider.accessId, cnameProvider.userId);
|
||||||
const context = { access, logger, http, utils };
|
const context = { access, logger, http, utils };
|
||||||
const dnsProvider: IDnsProvider = await createDnsProvider({
|
const dnsProvider: IDnsProvider = await createDnsProvider({
|
||||||
dnsProviderType: cnameProvider.dnsProviderType,
|
dnsProviderType: cnameProvider.dnsProviderType,
|
||||||
|
|
|
@ -11,4 +11,8 @@ export class AccessGetter implements IAccessService {
|
||||||
async getById<T = any>(id: any) {
|
async getById<T = any>(id: any) {
|
||||||
return await this.getter<T>(id, this.userId);
|
return await this.getter<T>(id, this.userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getCommonById<T = any>(id: any) {
|
||||||
|
return await this.getter<T>(id, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -107,14 +107,20 @@ export class AccessService extends BaseService<AccessEntity> {
|
||||||
return await super.update(param);
|
return await super.update(param);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getById(id: any, userId: number): Promise<any> {
|
async getAccessById(id: any, checkUserId: boolean, userId?: number): Promise<any> {
|
||||||
const entity = await this.info(id);
|
const entity = await this.info(id);
|
||||||
if (entity == null) {
|
if (entity == null) {
|
||||||
throw new Error(`该授权配置不存在,请确认是否已被删除:id=${id}`);
|
throw new Error(`该授权配置不存在,请确认是否已被删除:id=${id}`);
|
||||||
}
|
}
|
||||||
if (userId !== entity.userId && entity.userId !== 0) {
|
if (checkUserId) {
|
||||||
throw new PermissionException('您对该Access授权无访问权限');
|
if (userId == null) {
|
||||||
|
throw new ValidateException('userId不能为空');
|
||||||
|
}
|
||||||
|
if (userId !== entity.userId) {
|
||||||
|
throw new PermissionException('您对该Access授权无访问权限');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// const access = accessRegistry.get(entity.type);
|
// const access = accessRegistry.get(entity.type);
|
||||||
const setting = this.decryptAccessEntity(entity);
|
const setting = this.decryptAccessEntity(entity);
|
||||||
const input = {
|
const input = {
|
||||||
|
@ -124,6 +130,10 @@ export class AccessService extends BaseService<AccessEntity> {
|
||||||
return newAccess(entity.type, input);
|
return newAccess(entity.type, input);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getById(id: any, userId: number): Promise<any> {
|
||||||
|
return await this.getAccessById(id, true, userId);
|
||||||
|
}
|
||||||
|
|
||||||
decryptAccessEntity(entity: AccessEntity): any {
|
decryptAccessEntity(entity: AccessEntity): any {
|
||||||
let setting = {};
|
let setting = {};
|
||||||
if (entity.encryptSetting && entity.encryptSetting !== '{}') {
|
if (entity.encryptSetting && entity.encryptSetting !== '{}') {
|
||||||
|
|
|
@ -8,7 +8,7 @@ export class CnameProxyService implements ICnameProxyService {
|
||||||
this.getter = getter;
|
this.getter = getter;
|
||||||
}
|
}
|
||||||
|
|
||||||
getByDomain(domain: string): Promise<CnameRecord> {
|
async getByDomain(domain: string): Promise<CnameRecord> {
|
||||||
return this.getter<CnameRecord>(domain, this.userId);
|
return await this.getter<CnameRecord>(domain, this.userId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -354,7 +354,7 @@ export class PipelineService extends BaseService<PipelineEntity> {
|
||||||
role: userIsAdmin ? 'admin' : 'user',
|
role: userIsAdmin ? 'admin' : 'user',
|
||||||
};
|
};
|
||||||
const accessGetter = new AccessGetter(userId, this.accessService.getById.bind(this.accessService));
|
const accessGetter = new AccessGetter(userId, this.accessService.getById.bind(this.accessService));
|
||||||
const cnameProxyService = new CnameProxyService(userId, this.cnameRecordService.getByDomain.bind(this.cnameRecordService));
|
const cnameProxyService = new CnameProxyService(userId, this.cnameRecordService.getWithAccessByDomain.bind(this.cnameRecordService));
|
||||||
const executor = new Executor({
|
const executor = new Executor({
|
||||||
user,
|
user,
|
||||||
pipeline,
|
pipeline,
|
||||||
|
|
Loading…
Reference in New Issue